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

      if (argString.startsWith("-")) {

        parseArgumentCharacters(argString.substring(1));

      } else {

        currentArgument.previous();


Листинг 14.2 (продолжение)

        break;

      }

    }

  }


  private void parseArgumentCharacters(String argChars) throws ArgsException {

    for (int i = 0; i < argChars.length(); i++)

      parseArgumentCharacter(argChars.charAt(i));

  }


  private void parseArgumentCharacter(char argChar) throws ArgsException {

    ArgumentMarshaler m = marshalers.get(argChar);

    if (m == null) {

      throw new ArgsException(UNEXPECTED_ARGUMENT, argChar, null);

    } else {

      argsFound.add(argChar);

      try {

        m.set(currentArgument);

      } catch (ArgsException e) {

        e.setErrorArgumentId(argChar);

        throw e;

      }

    }

  }


  public boolean has(char arg) {

    return argsFound.contains(arg);

  }


  public int nextArgument() {

    return currentArgument.nextIndex();

  }


  public boolean getBoolean(char arg) {

    return BooleanArgumentMarshaler.getValue(marshalers.get(arg));

  }


  public String getString(char arg) {

    return StringArgumentMarshaler.getValue(marshalers.get(arg));

  }


  public int getInt(char arg) {

    return IntegerArgumentMarshaler.getValue(marshalers.get(arg));

  }


  public double getDouble(char arg) {

    return DoubleArgumentMarshaler.getValue(marshalers.get(arg));

  }


  public String[] getStringArray(char arg) {

    return StringArrayArgumentMarshaler.getValue(marshalers.get(arg));

  }

}

Обратите внимание: код читается сверху вниз, и вам не приходится постоянно переходить туда-сюда или заглядывать вперед. Единственное место, где все же необходимо заглянуть вперед, — это определение ArgumentMarshaler, но и это было сделано намеренно. Внимательно прочитав этот код, вы поймете, что собой представляет интерфейс ArgumentMarshaler и что делают производные классы. Примеры таких классов приведены в листингах 14.3–14.6.


Листинг 14.3. ArgumentMarshaler.java

public interface ArgumentMarshaler {

  void set(Iterator currentArgument) throws ArgsException;

}


Листинг 14.4. BooleanArgumentMarshaler.java

public class BooleanArgumentMarshaler implements ArgumentMarshaler {

  private boolean booleanValue = false;


  public void set(Iterator currentArgument) throws ArgsException {

    booleanValue = true;

  }


  public static boolean getValue(ArgumentMarshaler am) {

    if (am != null && am instanceof BooleanArgumentMarshaler)

      return ((BooleanArgumentMarshaler) am).booleanValue;

    else

      return false;

  }

}


Листинг 14.5. StringArgumentMarshaler.java

import static com.objectmentor.utilities.args.ArgsException.ErrorCode.*;


public class StringArgumentMarshaler implements ArgumentMarshaler {

  private String stringValue = "";


  public void set(Iterator currentArgument) throws ArgsException {

    try {

      stringValue = currentArgument.next();

    } catch (NoSuchElementException e) {

      throw new ArgsException(MISSING_STRING);

    }

  }


  public static String getValue(ArgumentMarshaler am) {

    if (am != null && am instanceof StringArgumentMarshaler)


Листинг 14.5. (продолжение)

      return ((StringArgumentMarshaler) am).stringValue;

    else

      return "";

  }

}


Листинг 14.6. IntegerArgumentMarshaler.java

import static com.objectmentor.utilities.args.ArgsException.ErrorCode.*;


public class IntegerArgumentMarshaler implements ArgumentMarshaler {

  private int intValue = 0;


  public void set(Iterator currentArgument) throws ArgsException {

    String parameter = null;

    try {

      parameter = currentArgument.next();

      intValue = Integer.parseInt(parameter);

    } catch (NoSuchElementException e) {

      throw new ArgsException(MISSING_INTEGER);

    } catch (NumberFormatException e) {

      throw new ArgsException(INVALID_INTEGER, parameter);

    }

  }


  public static int getValue(ArgumentMarshaler am) {

    if (am != null && am instanceof IntegerArgumentMarshaler)

      return ((IntegerArgumentMarshaler) am).intValue;

    else

      return 0;

  }

}

Другие классы, производные от ArgumentMarshaler, строятся по тому же шаблону, что и классы для массивов double и String. Здесь они не приводятся для экономии места. Оставляю их вам для самостоятельной работы.

Возможно, вы заметили еще одно обстоятельство: где определяются константы для кодов ошибок? Они находятся в классе ArgsException (листинг 14.7).


Листинг 14.7. ArgsException.java

import static com.objectmentor.utilities.args.ArgsException.ErrorCode.*;


public class ArgsException extends Exception {

  private char errorArgumentId = '\0';

  private String errorParameter = null;

  private ErrorCode errorCode = OK;


  public ArgsException() {}


  public ArgsException(String message) {super(message);}

  public ArgsException(ErrorCode errorCode) {

    this.errorCode = errorCode;

  }


  public ArgsException(ErrorCode errorCode, String errorParameter) {

    this.errorCode = errorCode;

    this.errorParameter = errorParameter;

  }


  public ArgsException(ErrorCode errorCode,

                       char errorArgumentId, String errorParameter) {

    this.errorCode = errorCode;

    this.errorParameter = errorParameter;

    this.errorArgumentId = errorArgumentId;

  }


  public char getErrorArgumentId() {

    return errorArgumentId;

  }


  public void setErrorArgumentId(char errorArgumentId) {