Skip to content

Commit

Permalink
✨ 14. 점진적인 개선 - 리팩토링 완료 (목록 14-1~7) (#17)
Browse files Browse the repository at this point in the history
* ✨ 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
viiviii authored May 12, 2022
1 parent 4a0570d commit e94aa34
Show file tree
Hide file tree
Showing 16 changed files with 1,160 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/main/java/chapter14/Application.java
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);
}
}
107 changes: 107 additions & 0 deletions src/main/java/chapter14/args/Args.java
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));
}
}
92 changes: 92 additions & 0 deletions src/main/java/chapter14/args/ArgsException.java
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
}
}
7 changes: 7 additions & 0 deletions src/main/java/chapter14/args/ArgumentMarshaler.java
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 src/main/java/chapter14/args/BooleanArgumentMarshaler.java
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;
}
}
}
32 changes: 32 additions & 0 deletions src/main/java/chapter14/args/DoubleArgumentMarshaler.java
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 src/main/java/chapter14/args/IntegerArgumentMarshaler.java
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;
}
}
}
27 changes: 27 additions & 0 deletions src/main/java/chapter14/args/StringArgumentMarshaler.java
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 "";
}
}
}
Loading

0 comments on commit e94aa34

Please sign in to comment.