-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ 14. 점진적인 개선 - 리팩토링 완료 (목록 14-1~7) (#17)
* ✨ 14. 점진적인 개선 - Only boolean (#2) * feat: Boolean 인수만 지원하던 초기 버전 / 목록 14-9 * test: Boolean 인수만 지원하던 초기 버전 테스트 추가 * 🚚 Args 클래스 패키지 안으로 이동 * ✨ 14. 점진적인 개선 - Add String (#3) * feat: String 인수 유형 추가 버전 / 목록 14-10 * test: String 인수 유형 추가 버전 테스트 추가 * fix: schema 오타 수정 * ✨ 14. 점진적인 개선 - Add Integer (&before refactoring ver) (#4) * feat: int 유형 추가 * test: int 유형 테스트 추가 * test: 기존 테스트를 책에 나온 테스트와 메서드명 및 순서 맞춤 * feat: 유효하지 않은 Schema element를 예외 처리 * refactor: 책과 순서 맞춤 및 메서드명 변경 등 작은 리팩토링 * refactor: UNEXPECTED_ARGUMENT errorCode 추가하여 리팩토링 * feat: ArgsException 추가 * refactor: errorArgument -> errorArgumentId로 변수명 변경 * test: 빠진 테스트spacesInFormat() 추가 * test: 값이 없는 경우 테스트 변경 * test: 잘못된 타입으로 호출한 경우 테스트 추가 * ✨ 14. 점진적인 개선 - 리팩토링 version 1 (#7) * 1. ArgumentMarshaler class 골격 추가 (목록 14-11) * 2. booleanArgs의 인수 타입을 ArgumentMarshaler로 변경 * 3. getBoolean() NullPointException 발생하는 경우 처리 * 4. StringArgs도 이전 단계처럼 변경 * 5. intArgs도 이전 단계처럼 변경 * 6. ArgumentMarshaler에 있는 boolean 관련 로직을 subclass인 BooleanArgumentMarshaler로 이동 * 7. String 로직도 StringArgumentMarshaler로 이동 * 8. int 로직도 IntergerArgumentMarshaler로 이동 * 9. Args Map 3개를 없애기 위해 marshalers map을 만들어 교체 * 10: marshalers.get() 호출 코드 제거하여 한 곳에서 처리 * 11. 불필요해진 isxxxArgs 메서드를 인라인 코드로 만들고 제거 * 12. setxxx()가 ArgumentMarshaler를 파라미터로 받아 사용하도록 * 13. booleanArgs Map 제거 * 14. stringArgs, intArgs Map도 모두 제거 * 15. 이제 잘 사용하지 않는 parse 메서드들을 인라인으로 변경하여 제거 * ✨ 14. 점진적인 개선 - 리팩토링 version 2 (#9) * 1. args 배열을 list로 변환 후 setxxxArg()에서 Iterator를 사용하도록 변경 * 2. setArgument()의 if-else 연쇄를 제거하기 위해 오류 로직을 분리 * 3. setBooleanArg()가 Iterator를 파라미터로 받도록 변경 * 4. ArgumentMarshaler set()을 직접 사용하여 setBooleanArg() 제거 * 5. setStringArg(), setIntArg() 제거 * 6. setArgument()의 타입을 일일히 확인하던 코드 제거 * 7. ArgumentMarshaler를 인터페이스로 변경 * ✨ 14. 점진적인 개선 - 리팩토링 version 3 (Add Double) (#10) * test: double 유형 테스트 추가 * refactor: isxxxSchemaElement() 인라인으로 변경하여 제거 * feat: double 유형 추가 * ✨ 14. 점진적인 개선 - 리팩토링 version 4 (#11) * 1. ErrorCode ArgsException class로 이동 * 2. ParseException 대신 ArgsException을 던지도록 변경 * 3. 예외 관련 로직 ArgsException으로 복사 * 4. parse()의 빈 catch절 제거하여 ArgsException을 던지게 변경 * 5. 예외에서 값을 꺼내도록 예외 테스트 코드 변경 * 6. UNEXPECTED_ARGUMENT도 ArgsException을 던지도록 변경 * 7. UNEXPECTED_ARGUMENT 예외 메세지 변경 * 8. 예외에서 값을 꺼내도록 예외 테스트 코드 변경 * 9. Args에서 불필요해진 예외 코드 제거 * 10. ArgsException 클래스 추출 * 11. ArgumentMarshaler 관련 클래스 추출 * 12. Args isValid 제거 * 13. INVALID_ARGUMENT_NAME, FORMAT errorCode 추가 * 14. 메서드 순서 변경 등 책이랑 맞춤 * ✨ 14. 점진적인 개선 - 리팩토링 version 5 (Final) (#14) * 1. 사용하지 않는 usage() 제거 * 2. schema 필드 제거 * 3. argList 필드 제거 및 메서드명 변경 * 4. parsexxx() 리팩토링 * 5. cardinality() 제거 * 6. getxxx() 내부 로직을 타입별 ArgumentMarshaler로 이동 * 7. ArgumentMarshaler get() 제거 * 8. 책과 동일하게 메서드 순서 및 괄호 등 format 맞춤 * 9. ErrorCode.OK errorMessage 변경 * 10. 사용 코드 목록 14-1과 동일하게 변경
- Loading branch information
Showing
16 changed files
with
1,160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package chapter14; | ||
|
||
import chapter14.args.Args; | ||
import chapter14.args.ArgsException; | ||
|
||
class Application { | ||
|
||
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'); | ||
executeApplication(logging, port, directory); | ||
} catch (ArgsException e) { | ||
System.out.printf("Argument error: %s\n", e.errorMessage()); | ||
} | ||
} | ||
|
||
// stub | ||
private static void executeApplication(boolean logging, int port, String directory) { | ||
System.out.printf("logging: %b, port: %d, directory: %s\n", logging, port, directory); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package chapter14.args; | ||
|
||
import java.util.*; | ||
|
||
import static chapter14.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<>(); | ||
argsFound = new HashSet<>(); | ||
|
||
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 | ||
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)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package chapter14.args; | ||
|
||
public class ArgsException extends Exception { | ||
private char errorArgumentId = '\0'; | ||
private String errorParameter = "TILT"; | ||
private ErrorCode 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.errorArgumentId = errorArgumentId; | ||
this.errorParameter = errorParameter; | ||
} | ||
|
||
public char getErrorArgumentId() { | ||
return errorArgumentId; | ||
} | ||
|
||
public void setErrorArgumentId(char errorArgumentId) { | ||
this.errorArgumentId = errorArgumentId; | ||
} | ||
|
||
public String getErrorParameter() { | ||
return errorParameter; | ||
} | ||
|
||
public void setErrorParameter(String errorParameter) { | ||
this.errorParameter = errorParameter; | ||
} | ||
|
||
public ErrorCode getErrorCode() { | ||
return errorCode; | ||
} | ||
|
||
public void setErrorCode(ErrorCode errorCode) { | ||
this.errorCode = errorCode; | ||
} | ||
|
||
public String errorMessage() { | ||
switch (errorCode) { | ||
case OK: | ||
return "TILT: Should not get here."; | ||
case UNEXPECTED_ARGUMENT: | ||
return String.format("Argument(s) -%c unexpected.", errorArgumentId); | ||
case MISSING_STRING: | ||
return String.format("Could not find string parameter for -%c.", | ||
errorArgumentId); | ||
case INVALID_INTEGER: | ||
return String.format("Argument -%c expects an integer but was '%s'.", | ||
errorArgumentId, errorParameter); | ||
case MISSING_INTEGER: | ||
return String.format("Could not find integer parameter for -%c.", | ||
errorArgumentId); | ||
case INVALID_DOUBLE: | ||
return String.format("Argument -%c expects an double but was '%s'.", | ||
errorArgumentId, errorParameter); | ||
case MISSING_DOUBLE: | ||
return String.format("Could not find double parameter for -%c.", | ||
errorArgumentId); | ||
case INVALID_ARGUMENT_NAME: | ||
return String.format("'%c' is not a valid argument name.", | ||
errorArgumentId); | ||
case INVALID_ARGUMENT_FORMAT: | ||
return String.format("'%s' is not a valid argument format.", | ||
errorParameter); | ||
} | ||
return ""; | ||
} | ||
|
||
public enum ErrorCode { | ||
OK, INVALID_ARGUMENT_FORMAT, UNEXPECTED_ARGUMENT, | ||
INVALID_ARGUMENT_NAME, | ||
MISSING_STRING, | ||
MISSING_INTEGER, INVALID_INTEGER, | ||
MISSING_DOUBLE, INVALID_DOUBLE | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package chapter14.args; | ||
|
||
import java.util.Iterator; | ||
|
||
public interface ArgumentMarshaler { | ||
void set(Iterator<String> currentArgument) throws ArgsException; | ||
} |
20 changes: 20 additions & 0 deletions
20
src/main/java/chapter14/args/BooleanArgumentMarshaler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package chapter14.args; | ||
|
||
import java.util.Iterator; | ||
|
||
public class BooleanArgumentMarshaler implements ArgumentMarshaler { | ||
private boolean booleanValue = false; | ||
|
||
@Override | ||
public void set(Iterator<String> currentArgument) throws ArgsException { | ||
booleanValue = true; | ||
} | ||
|
||
public static boolean getValue(ArgumentMarshaler am) { | ||
if (am != null && am instanceof BooleanArgumentMarshaler) { | ||
return ((BooleanArgumentMarshaler) am).booleanValue; | ||
} else { | ||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package chapter14.args; | ||
|
||
import java.util.Iterator; | ||
import java.util.NoSuchElementException; | ||
|
||
import static chapter14.args.ArgsException.ErrorCode.INVALID_DOUBLE; | ||
import static chapter14.args.ArgsException.ErrorCode.MISSING_DOUBLE; | ||
|
||
public class DoubleArgumentMarshaler implements ArgumentMarshaler { | ||
private double doubleValue = 0; | ||
|
||
@Override | ||
public void set(Iterator<String> currentArgument) throws ArgsException { | ||
String parameter = null; | ||
try { | ||
parameter = currentArgument.next(); | ||
doubleValue = Double.parseDouble(parameter); | ||
} catch (NoSuchElementException e) { | ||
throw new ArgsException(MISSING_DOUBLE); | ||
} catch (NumberFormatException e) { | ||
throw new ArgsException(INVALID_DOUBLE, parameter); | ||
} | ||
} | ||
|
||
public static double getValue(ArgumentMarshaler am) { | ||
if (am != null && am instanceof DoubleArgumentMarshaler) { | ||
return ((DoubleArgumentMarshaler) am).doubleValue; | ||
} else { | ||
return 0.0; | ||
} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/chapter14/args/IntegerArgumentMarshaler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package chapter14.args; | ||
|
||
import java.util.Iterator; | ||
import java.util.NoSuchElementException; | ||
|
||
import static chapter14.args.ArgsException.ErrorCode.INVALID_INTEGER; | ||
import static chapter14.args.ArgsException.ErrorCode.MISSING_INTEGER; | ||
|
||
public class IntegerArgumentMarshaler implements ArgumentMarshaler { | ||
private int intValue = 0; | ||
|
||
@Override | ||
public void set(Iterator<String> 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; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package chapter14.args; | ||
|
||
import java.util.Iterator; | ||
import java.util.NoSuchElementException; | ||
|
||
import static chapter14.args.ArgsException.ErrorCode.MISSING_STRING; | ||
|
||
public class StringArgumentMarshaler implements ArgumentMarshaler { | ||
private String stringValue = ""; | ||
|
||
@Override | ||
public void set(Iterator<String> 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) { | ||
return ((StringArgumentMarshaler) am).stringValue; | ||
} else { | ||
return ""; | ||
} | ||
} | ||
} |
Oops, something went wrong.