Чистый код. Создание, анализ и рефакторинг — страница 38 из 94

Добавление поддержки String было очень похоже на добавление поддержки Boolean. Мне предстояло изменить HashMap и заставить работать функции parse, set и get. Полагаю, следующий код понятен без пояснений — если не считать того, что я разместил всю реализацию компоновки аргументов в базовом клссе ArgumentMarshaller, вместо того чтобы распределять ее по производным классам.

private Map stringArgs =

      new HashMap();

...

private void parseStringSchemaElement(char elementId) {

  stringArgs.put(elementId, new StringArgumentMarshaler());

}

...

private void setStringArg(char argChar) throws ArgsException {

  currentArgument++;

  try {

    stringArgs.get(argChar).setString(args[currentArgument]);

  } catch (ArrayIndexOutOfBoundsException e) {

    valid = false;

    errorArgumentId = argChar;

    errorCode = ErrorCode.MISSING_STRING;

    throw new ArgsException();

  }

}

...

public String getString(char arg) {

  Args.ArgumentMarshaler am = stringArgs.get(arg);

  return am == null ? "" : am.getString();

}

...

private class ArgumentMarshaler {

  private boolean booleanValue = false;

  private String stringValue;


  public void setBoolean(boolean value) {

    booleanValue = value;

  }

  public boolean getBoolean() {

    return booleanValue;

  }


  public void setString(String s) {

    stringValue = s;

  }


  public String getString() {

    return stringValue == null ? "" : stringValue;

  }

}

И снова изменения вносились последовательно и только так, чтобы тесты по крайней мере хотя бы запускались (даже если и не проходили). Если работоспособность теста была нарушена, я сначала добивался того, чтобы он работал, и только потом переходил к следующему изменению.

Вероятно, вы уже поняли, что я собираюсь сделать. Собрав все текущее поведение компоновки аргументов в базовом классе ArgumentMarshaler, я намерен перемещать его вниз в производные классы. Это позволит мне сохранить работоспособность программы в ходе постепенного изменения ее структуры.

Очевидным следующим шагом стало перемещение функциональности аргумента int в ArgumentMarshaler. И снова все обошлось без сюрпризов:

private Map intArgs =

     new HashMap();

...

private void parseIntegerSchemaElement(char elementId) {

  intArgs.put(elementId, new IntegerArgumentMarshaler());