クリーンコード第14章


第14章徐々に改善


本の冒頭で、良いコードを書くために、まず編んでから整理します.ドラフトコードは、改善に有利なコードを徐々に形成しなければならない.
public static void main(String[] args) {
	try {
		Args arg = new Args("l,p#,d*", args);
		boolean logging = arg.getBoolean('l');
		int port = arg.getInt('p');
		String directory = arg.getString('d');
		executeAppliocation(logging, port, directory);
	} catch (ArgsException e) {
		System.out.printf("Argument error: %s\n", e.errorMessage());
	}
}
この章で分析する例は、上記のコードに基づいています.

ユーティリティアレイ


プログラミングプログラムを作成するには、コマンドラインファクタの構文を分析する必要があります.適切なユーティリティがない場合は、直接分析をmain関数のパラメータargsに変換します.直接実装されるユーティリティをArgsと呼ぶ.

Argsの実装

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

public class Args {
	private Map<Character, ArgumentMarshaler> marshalers;
	private Set<Character> argsFound;
	private ListIterator<String> currentArgument;

	public Args(String schema, String[] args) throws ArgsException {
		marshalers = new HashMap<Character, ArgumentMarshaler>();
		argsFound = new HashSet<Character>();
    
    parseSchema(schema);
    parseArgumentStrings(Arrays.asList(args)); 
  }
  
  private void parseSchema(String schema) throws ArgsException { 
    for (String element : schema.split(","))
      if (element.length() > 0) 
        parseSchemaElement(element.trim());
  }
  
  private void parseSchemaElement(String element) throws ArgsException { 
    char elementId = element.charAt(0);
    String elementTail = element.substring(1); validateSchemaElementId(elementId);
    if (elementTail.length() == 0)
      marshalers.put(elementId, new BooleanArgumentMarshaler());
    else if (elementTail.equals("*")) 
      marshalers.put(elementId, new StringArgumentMarshaler());
    else if (elementTail.equals("#"))
      marshalers.put(elementId, new IntegerArgumentMarshaler());
    else if (elementTail.equals("##")) 
      marshalers.put(elementId, new DoubleArgumentMarshaler());
else if (elementTail.equals("[*]"))
      marshalers.put(elementId, new StringArrayArgumentMarshaler());
    else
      throw new ArgsException(INVALID_ARGUMENT_FORMAT, elementId, elementTail);
  }
  
  private void validateSchemaElementId(char elementId) throws ArgsException { 
    if (!Character.isLetter(elementId))
      throw new ArgsException(INVALID_ARGUMENT_NAME, elementId, null); 
  }
  
  private void parseArgumentStrings(List<String> argsList) throws ArgsException {
    for (currentArgument = argsList.listIterator(); currentArgument.hasNext();) {
      String argString = currentArgument.next(); 
      if (argString.startsWith("-")) {
        parseArgumentCharacters(argString.substring(1)); 
      } else {
        currentArgument.previous();
        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));
  } 
}
本のコードはこうです.かなりきれいです.ひとつひとつの分析ではなく、ずっと読んでいくとこんな鼻になるのではないでしょうか.そして感じました.
しかし、最初からこのようなコードを書くことはできません.上のコードは非常に汚い草案コードを徐々に改善してきたものです.

Args草案


初期コードがどのように組織されているかを説明するには...Booleanを買収したベンチャー企業のコードを分析するしかないのは悪くない.しかし、上記の簡潔な最終コードとは異なります.(正しいコードはCLINコード261 p)Booleanパラメータのみ(?)関数がたくさんあります...例外的にStringとIntegerの買収分析も追加され、結果はかなり雑然としたものになった.
🙋‍♀️だから止まった
続けて進めば、どうしても番組が完成しますが、そうなるとコードがさらに悪くなります.
したがって,著者らは機能を追加するのではなく,再設計を開始する.
  • 買収タイプのHashMapを選択するために、アーキテクチャ要素の分析部分が追加されました.
  • 2.コマンドライン引数から引数タイプを解析し、真のタイプに変換します.
  • getXXXメソッドを実装し、真のタイプを呼び出し者に返す.買収のタイプは多様であるが,全員が同様の方法を提供しているため,1つのクラスが適切であると考えられる.そのため、著者はArgumentMarshalerの概念を誕生させた.
  • (を参照)
    最終コードを読むと、ArgumentMarshalerがインタフェースであることがわかります.最終コードには名前(?)のみが含まれます.ArgumentMarshalerを簡単に紹介します...新しいパラメータタイプを追加するには、ArgumentMarshalerクラスから新しいクラスを派生し、getXXX関数を追加し、parseSchemaElement関数に新しいcase文を追加する必要があります.
    🔎段階的に改善する.
    凱旋という名前の下では、構造を大きく割引してプログラムを破壊する可能性があります.これでは、改善試合のようにプログラムを実行するのは難しい.
    したがって,テスト主導開発(TDD)技術を用いるべきである.システムが改善された後もすべてのテスト例に合格した場合、正しく動作していると考えられます.

    n/a.結論


    ループのコードだけでは足りない.草案を作成した後、TDD技術を使用して、簡潔で簡単なコードを書くために少しずつ改善します.
    コード注意:https://han.gl/TghVb