ํด๋น ๋ถ๋ถ์ ๋๋ฌด ์ฝ๋๊ฐ ๋ง์, ์ด์ ์ํ์ ์ดํ ์ํ๋ฅผ ๋๊ณ ๊ทธ ์ฌ์ด์์ ์ ์๊ฐ ์ด๋ ํ ํ๋ฆ์ผ๋ก ์ด๋ฅผ ์ฒ๋ฆฌํ๋์ง ๊ฐ๋ตํ๊ฒ ์ ๋ฆฌํ๋ ๊ฒ์ ๋ชฉ์ ์ผ๋ก ํ๋ค.
Intro
ํด๋น ๋ถ๋ถ์์๋ ์ถ๋ฐ์ ์ข์์ผ๋, ํ์ฅ์์ ๋ถ์กฑํ๋ ๋ชจ๋์ ์๊ฐํ๋ค. ๊ทธ ๋ค์, ์ด๋ฅผ ๊ฐ์ ํ๊ณ ์ ๋ฆฌํ๋ ๋จ๊ณ๋ฅผ ์์ฐจ์ ์ผ๋ก ์์๋ณผ ์์ ์ด๋ค.
๋ค์์ ์ฝ๋๋ ๋ช
๋ นํ ์ธ์์ ๊ตฌ๋ฌธ์ ๋ถ์ํ๋ ํด๋์ค Args
๋ค. ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค.
public static void main(String[] args) {
try {
Args arg = new Args("l,p#,d*", args); // ํ์ ์ค์ : Bool, Int, String, args ์ธ์๋ก ๋๊น
boolean logging = arg.getBoolean('l'); // arg๋ก ํ์ฑ๋ ๊ฐ์ ๋ฐ์ ๋ณ์ ์ด๋ฆ์ผ๋ก ์๋ฏธ ๋ถ์ฌ
int port = arg.getInt('p');
String directory = arg.getString('d');
executeApplication(logging, port, directory);
} catch (ArgsException e) {
System.out.print("Argument error: %s\n", e.errorMessage());
}
}
ArgsException์ด ๋ฐ์ํ์ง ์๋๋ค๋ฉด ๋ช
๋ นํ ์ธ์์ ๊ตฌ๋ฌธ์ ์ฑ๊ณต์ ์ผ๋ก ๋ถ์ํ์ผ๋ฉฐ Args ์ธ์คํด์ค์ ์ง์๋ฅผ ๋์ ธ๋ ์ข๋ค๋ ๋ง์ด๋ค. ์ธ์ ๊ฐ์ ๊ฐ์ ธ์ค๊ธฐ ์ํด get~()
๋ฑ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค.
Args ๊ตฌํ
์ด์ ํด๋น ํด๋์ค๋ฅผ ์ด๋ป๊ฒ ๊ตฌํํ๋์ง ์ ์ด๋ณด๊ฒ ๋ค. ์ด๋ฆ, ํจ์ ํฌ๊ธฐ, ์ฝ๋ ํ์์ ์ฃผ๋ชฉํ๋ฉฐ ์ฝ๋๋ค.
Args.java
package com.objectmentor.utilities.args;
import static com.objectmentor.utilities.args.ArgsException.ErrorCode.*;
import java.util.*;
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); // 1๏ธโฃ
parseArgumentStrings(Arrays.asList(args)); // 2๏ธโฃ
}
// 1๏ธโฃ
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);
}
// 2๏ธโฃ
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));
}
}
์์์ ์๋๋ก ์ฝ๋๊ฐ ๋ฌผ ํ๋ฅด๋ฏ ์ฝํ๋ค. ๋ฐ๊นฅ์ชฝ์์ ์ฌ์ฉํ๋ method๋ ์ต์๋จ์ ์์นํด์๊ณ , ์๋๋ก ๋ด๋ ค๊ฐ ์๋ก ๊ตฌ์ฒด์ ์ธ ๊ตฌํ์ด ๋์ด๋์ด ์๋ค. ํ ๊ฐ์ง ๋จผ์ ์ฝ์ด๋ณผ ์ฝ๋๊ฐ ์๋ค๋ฉด ArgumentMarshaler
์ ์์ด๋ค. ์๋์ ์ ์๋์ด ์๋ ArgumentMarshaler
๊ฐ ๋ฐ๋ฅด๋ interface์ด๋ค.
ArgumentMarshaler.java
public interface ArgumentMarshaler {
void set(Iterator<String> currentArgument) throws ArgsException;
}
BooleanArgumentMarshaler.java
public class BooleanArgumentMarshaler implements ArgumentMarshaler {
private boolean booleanValue = false;
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;
}
}
StringArgumentMarshaler.java
import static com.objectmentor.utilities.args.ArgsException.ErrorCode.*;
public class StringArgumentMarshaler implements ArgumentMarshaler {
private String stringValue = "";
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 "";
}
}
IntegerArgumentMarshaler.java
import static com.objectmentor.utilities.args.ArgsException.ErrorCode.*;
public class IntegerArgumentMarshaler implements ArgumentMarshaler {
private int intValue = 0;
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;
}
}
DoubleArgumentMarshaler
, StringArrayArgumentMarshaler
๋ ํจํด์ด ๊ฐ์ ์๋ตํ๋ค. ํด๋น ์ฝ๋๋ฅผ ๋ณด๋ค๊ฐ ์๋ฌธ์ด ๋๋ ๊ฒ์ด ํ๋ ์๋ค๋ฉด, ๋ฐ๋ก Error ์ฒ๋ฆฌ์ด๋ค.
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) {
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 -%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 a 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
}
}
์ ๋ฆฌ
๊ต์ฅํ ๋จ์ํ ๊ฐ๋ ์์๋ ๋ถ๊ตฌํ๊ณ ์ฝ๋๊ฐ ๋ง์ด ํ์ํ๋ค. ์ด๋ฅผ ์ ์ ํ์ ์ธ์ด์ธ ์๋ฐ๋ฅผ ์ฌ์ฉํด์ ์ด๋ค. (Swift๋ ๋ํ ์ง๋) ํ์ง๋ง ์ฝ์ด๋ณด๋ฉด ์๊ฒ ์ง๋ง ๊ต์ฅํ ๊ตฌ์กฐ๋ ๊น๋ํ๊ณ ์์ง์ธ ํ๋ก๊ทธ๋จ์ด๋ค.
์ธ์ ์ ํ์ ์ถ๊ฐํ๊ธฐ ์ํด์๋ ArgumentMarshaler
๋ฅผ ์ฑํํ์ฌ get ํจ์๋ฅผ ์ถ๊ฐํ๊ณ , parseSchemaElement
ํจ์์ case ํ๋๋ง ์ถ๊ฐํ๋ฉด ๋๋ค.
์ด๋ป๊ฒ ์งฐ๋๋๊ณ ?
์ฒ์๋ถํฐ ์ด๋ ๊ฒ ๊ตฌํํ ์ ์์์๊น? ์๋๋ค. ์ ์ง์ ์ผ๋ก ๊ฐ์ ํ๋ค. ํ๋ก๊ทธ๋๋ฐ์ ๊ณผํ๋ณด๋ค ๊ณต์(craft)์ ๊ฐ๊น๋ค. ๊นจ๋ํ ์ฝ๋๋ฅผ ์ง๋ ค๋ฉด ๋จผ์ ์ง์ ๋ถํ ์ฝ๋๋ฅผ ์ง ๋ค์ ์ ๋ฆฌํด์ผ ํ๋ค๋ ์๋ฏธ์ด๋ค.
๋๋ค์์ ์ ์ฐธ ํ๋ก๊ทธ๋๋จธ๋ (๋๋ค์ ์ด๋ฉ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก) ์ด ์ถฉ๊ณ ๋ฅผ ์ถฉ์คํ ๋ฐ๋ฅด์ง ์๋๋ค. ๊ทธ๋ค์ ๋ฌด์กฐ๊ฑด ๋์๊ฐ๋ ํ๋ก๊ทธ๋จ์ ๋ชฉํ๋ก ์ก๋๋ค. ์ผ๋จ ํ๋ก๊ทธ๋จ์ด โ๋์๊ฐ๋ฉดโ ๋ค์ ์ ๋ฌด๋ก ๋์ด๊ฐ๋ค. โ๋์๊ฐ๋โ ํ๋ก๊ทธ๋จ์ ๊ทธ ์ํ๊ฐ ์ด๋ป๋ ๊ทธ๋๋ก ๋ฒ๋ ค๋๋ค. ๊ฒฝํ์ด ํ๋ถํ ์ ๋ฌธ ํ๋ก๊ทธ๋๋จธ๋ผ๋ฉด ์ด๋ฐ ํ๋์ด ์ ๋ฌธ๊ฐ๋ก์ ์์ด ํ์๋ผ๋ ์ฌ์ค์ ์ ์๋ค.
Args: 1์ฐจ ์ด์
๊ทธ๋ผ ์ฒ์์ ์ด ์ฝ๋๊ฐ ์ด๋ ๋์ง ํ์ธํด๋ณด์.
import java.text.ParseException;
import java.util.*;
public class Args {
private String schema;
private String[] args;
private boolean valid = true;
private Set<Character> unexpectedArguments = new TreeSet<Character>();
private Map<Character, Boolean> booleanArgs = new HashMap<Character, Boolean>();
private Map<Character, String> stringArgs = new HashMap<Character, String>();
private Map<Character, Integer> intArgs = new HashMap<Character, Integer>();
private Set<Character> argsFound = new HashSet<Character>();
private int currentArgument;
private char errorArgumentId = '\0';
private String errorParameter = "TILT";
private ErrorCode errorCode = ErrorCode.OK;
private enum ErrorCode {
OK, MISSING_STRING, MISSING_INTEGER, INVALID_INTEGER, UNEXPECTED_ARGUMENT}
public Args(String schema, String[] args) throws ParseException {
this.schema = schema;
this.args = args;
valid = parse();
}
private boolean parse() throws ParseException {
if (schema.length() == 0 && args.length == 0)
return true;
parseSchema();
try {
parseArguments();
} catch (ArgsException e) {
}
return valid;
}
private boolean parseSchema() throws ParseException {
for (String element : schema.split(",")) {
if (element.length() > 0) {
String trimmedElement = element.trim();
parseSchemaElement(trimmedElement);
}
}
return true;
}
private void parseSchemaElement(String element) throws ParseException {
char elementId = element.charAt(0);
String elementTail = element.substring(1);
validateSchemaElementId(elementId);
if (isBooleanSchemaElement(elementTail))
parseBooleanSchemaElement(elementId);
else if (isStringSchemaElement(elementTail))
parseStringSchemaElement(elementId);
else if (isIntegerSchemaElement(elementTail))
parseIntegerSchemaElement(elementId);
else
throw new ParseException(String.format("Argument: %c has invalid format: %s.", elementId, elementTail), 0);
}
}
private void validateSchemaElementId(char elementId) throws ParseException {
if (!Character.isLetter(elementId)) {
throw new ParseException("Bad character:" + elementId + "in Args format: " + schema, 0);
}
}
private void parseBooleanSchemaElement(char elementId) {
booleanArgs.put(elementId, false);
}
private void parseIntegerSchemaElement(char elementId) {
intArgs.put(elementId, 0);
}
private void parseStringSchemaElement(char elementId) {
stringArgs.put(elementId, "");
}
private boolean isStringSchemaElement(String elementTail) {
return elementTail.equals("*");
}
private boolean isBooleanSchemaElement(String elementTail) {
return elementTail.length() == 0;
}
private boolean isIntegerSchemaElement(String elementTail) {
return elementTail.equals("#");
}
private boolean parseArguments() throws ArgsException {
for (currentArgument = 0; currentArgument < args.length; currentArgument++) {
String arg = args[currentArgument];
parseArgument(arg);
}
return true;
}
private void parseArgument(String arg) throws ArgsException {
if (arg.startsWith("-"))
parseElements(arg);
}
private void parseElements(String arg) throws ArgsException {
for (int i = 1; i < arg.length(); i++)
parseElement(arg.charAt(i));
}
private void parseElement(char argChar) throws ArgsException {
if (setArgument(argChar))
argsFound.add(argChar);
else
unexpectedArguments.add(argChar);
errorCode = ErrorCode.UNEXPECTED_ARGUMENT;
valid = false;
}
private boolean setArgument(char argChar) throws ArgsException {
if (isBooleanArg(argChar))
setBooleanArg(argChar, true);
else if (isStringArg(argChar))
setStringArg(argChar);
else if (isIntArg(argChar))
setIntArg(argChar);
else
return false;
return true;
}
private boolean isIntArg(char argChar) {
return intArgs.containsKey(argChar);
}
private void setIntArg(char argChar) throws ArgsException {
currentArgument++;
String parameter = null;
try {
parameter = args[currentArgument];
intArgs.put(argChar, new Integer(parameter));
} catch (ArrayIndexOutOfBoundsException e) {
valid = false;
errorArgumentId = argChar;
errorCode = ErrorCode.MISSING_INTEGER;
throw new ArgsException();
} catch (NumberFormatException e) {
valid = false;
errorArgumentId = argChar;
errorParameter = parameter;
errorCode = ErrorCode.INVALID_INTEGER;
throw new ArgsException();
}
}
private void setStringArg(char argChar) throws ArgsException {
currentArgument++;
try {
stringArgs.put(argChar, args[currentArgument]);
} catch (ArrayIndexOutOfBoundsException e) {
valid = false;
errorArgumentId = argChar;
errorCode = ErrorCode.MISSING_STRING;
throw new ArgsException();
}
}
private boolean isStringArg(char argChar) {
return stringArgs.containsKey(argChar);
}
private void setBooleanArg(char argChar, boolean value) {
booleanArgs.put(argChar, value);
}
private boolean isBooleanArg(char argChar) {
return booleanArgs.containsKey(argChar);
}
public int cardinality() {
return argsFound.size();
}
public String usage() {
if (schema.length() > 0)
return "-[" + schema + "]";
else
return "";
}
public String errorMessage() throws Exception {
switch (errorCode) {
case OK:
throw new Exception("TILT: Should not get here.");
case UNEXPECTED_ARGUMENT:
return unexpectedArgumentMessage();
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);
}
return "";
}
private String unexpectedArgumentMessage() {
StringBuffer message = new StringBuffer("Argument(s) -");
for (char c : unexpectedArguments) {
message.append(c);
}
message.append(" unexpected.");
return message.toString();
}
private boolean falseIfNull(Boolean b) {
return b != null && b;
}
private int zeroIfNull(Integer i) {
return i == null ? 0 : i;
}
private String blankIfNull(String s) {
return s == null ? "" : s;
}
public String getString(char arg) {
return blankIfNull(stringArgs.get(arg));
}
public int getInt(char arg) {
return zeroIfNull(intArgs.get(arg));
}
public boolean getBoolean(char arg) {
return falseIfNull(booleanArgs.get(arg));
}
public boolean has(char arg) {
return argsFound.contains(arg);
}
public boolean isValid() {
return valid;
}
private class ArgsException extends Exception {
}
}
์ด๋ฐ ์ฝ๋๋ฅผ ์ฒ์๋ถํฐ ์๋ํ ๊ฒ์ ์๋์๋ค. ํจ์ ์ด๋ฆ์ด๋ ๋ณ์ ์ด๋ฆ์ ์ ํํ ๋ฐฉ์, ์ด์คํ์ง๋ง ๋๋ฆ๋๋ก ๊ตฌ์กฐ๊ฐ ์๋ค๋ ์ฌ์ค ๋ฑ์ด ๋ ธ๋ ฅ์ ์ฆ๊ฑฐ๋ค. ํ์ง๋ง ์ด๋ ์๊ฐ ํ๋ก๊ทธ๋จ์ ๋ด ์์ ๋ฒ์ด๋ฌ๋ค. ์ฒซ ๋ฒ์ ์ด๋ Boolean ์ธ์๋ง ์ง์ํ๋ ์ด๊ธฐ ๋ฒ์ ์์ String๊ณผ Integer ์ธ์ ์ ํ์ ์ถ๊ฐํ๋ฉด์ ๋ถํฐ ์ฌ์์ด ์์๋๋ค.
๊ทธ๋์ ๋ฉ์ท๋ค
์ถ๊ฐํ ์ธ์ ์ ํ์ด ์ ์ด๋ ๋ ๊ฐ๋ ๋ ์์์ง๋ง, ์ด ์ํ์์ ์ถ๊ฐํ๋ฉด ์ฝ๋๊ฐ ๋ ๋๋น ์ง ๊ฒ์ด๋ผ๋ ์ฌ์ค์ด ์๋ช ํ๋ค. ๊ณ์ ๋ฐ์ด๋ถ์ด๋ฉด ํ๋ก๊ทธ๋จ์ ์ด๋ป๊ฒ๋ ์์ฑํ๊ฒ ์ง๋ง ๊ทธ๋ฌ๋ค๊ฐ๋ ๋๋ฌด ์ปค์ ์๋๊ธฐ ์ด๋ ค์ด ๊ณจ์นซ๊ฑฐ๋ฆฌ๊ฐ ์๊ฒจ๋ ์ฐธ์ด์๋ค. ์ฝ๋ ๊ตฌ์กฐ๋ฅผ ์ ์ง๋ณด์ํ๊ธฐ ์ข์ ์ํ๋ก ๋ง๋ค๋ ค๋ฉด ์ง๊ธ์ด ์ ๊ธฐ๋ผ ํ๋จํ๋ค.
์ด๋ฐ ํ์ด๋ฐ์ ์ฌ์ค ์ฐ๋ฆฌ๊ฐ ์ฝ๋๋ฅผ ์ง๋ฉด์๋ ์์ฐ์ค์ ๋๋ผ๋ ํฌ์ธํธ์ด๋ค. ์ฆ, ์ง๊ธํ๋ ๋ฐฉ์์ ๊ณ ์งํ์ ๋ ์ป๋ ํจ์ฉ๋ณด๋ค, ์ข์ ๊ตฌ์กฐ๋ฅผ ์ ํํ์ฌ ์งํํ์ ๋ ์ป๋ ํจ์ฉ์ด ํฌ๋ค๊ณ ์ง๊ด์ ์ผ๋ก ๋๋ผ๋ ์ง์ ์ด๋ค. ๋ฆฌํฉํ ๋ง์ ํ๋ฉด์๋ ์ฝ๋๋ฅผ ์์ฑํ๋ฉด์ ๋๊ผ๋ ์ ์ ์ ๋ฆฌํ๋ค.
- ์ธ์ ์ ํ์ ์ถ๊ฐํ๋ฉด์, ์ ์ธ์ ์ ํ์ ์ถ๊ฐํ๊ธฐ ์ํด์๋ ์ฃผ์ ์ง์ ์ธ๊ณณ์ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค๋ ์ฌ์ค์ ์์๋ค.
- ๋ช ๋ นํ ์ธ์์์ ์ธ์ ์ ํ์ ๋ถ์ํด์ ์ง์ง ์ ํ์ผ๋ก ๋ณ๊ฒฝํด์ผ ํ๋ค.
- get~ ๋ฉ์๋๋ฅผ ํตํด ์ง์ง ์ ํ์ ๋ฐํํ๋ค.
์ด๋ฌํ ์กฐ๊ฑด์ ๊ธฐ๋ฐ์ผ๋ก ArgumentMarshaler
๋ผ๋ ๊ฐ๋
์ ๋ง๋ค์๋ค.
์ ์ง์ ์ผ๋ก ๊ฐ์ ํ๋ค
ํ๋ก๊ทธ๋จ์ ๋ง์น๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ ์ค ํ๋๋ ๊ฐ์ ์ด๋ผ๋ ์ด๋ฆ ์๋ ๊ตฌ์กฐ๋ฅผ ํฌ๊ฒ ๋ค์ง๋ ํ์๋ค. ์ด๋ฌํ ์ ์์ TDD๋ฅผ ์ฌ์ฉํ๋ค. ์ฆ, ์ธ์ ๋ผ๋ ์์คํ ์ด ๋์๊ฐ์ผ ํ๋ค๋ ์์น์ ์ ์ฉํ๊ธฐ ์ํ ์์ง๋ค.
๋ณ๊ฒฝ ์ ํ์ ์์คํ ์ ์ค์๋ ์ฌ๋ถ๋ฅผ ๊ฒ์ฆํ๊ธฐ ์ํด์๋ ์ธ์ ๋ ์คํ์ด ๊ฐ๋ฅํ Test Suit๊ฐ ํ์ํ๋ค. ์ด๋ฅผ ์ํด ํ์ฌ Class์ ๋์์ ํ์ธํ ์ ์๋ test case๋ฅผ ๋ง๋ค์ด ๋์๋ค. ์ด ์ฝ๋๋ค์ ํต๊ณผํ๋ค๋ฉด ์ฌ๋ฐ๋ก ๋์ํ๋ค๊ณ ๋ด๋ ๋ฌด๋ฐฉํ๋ค.
์ด ๋ค์์์ผ ์์คํ
์ ๋ณ๊ฒฝ์ ๊ฐํ๊ธฐ ์์ํ๋ค. ๋จผ์ , ArgumentMarshaler
์ ๊ณจ๊ฒฉ์ ์ถ๊ฐํ๋ค.
private class ArgumentMarshaler {
private boolean booleanValue = false;
public void setBoolean(boolean value) {
booleanValue = value;
}
public boolean getBoolean() {return booleanValue;}
}
private class BooleanArgumentMarshaler extends ArgumentMarshaler { }
private class StringArgumentMarshaler extends ArgumentMarshaler { }
private class IntegerArgumentMarshaler extends ArgumentMarshaler { }
๊ทธ ๋ค์์ผ๋ก
// AS-IS
public class Args {
private Map<Character, Boolean> booleanArgs = new HashMap<Character, Boolean>();
...
private void parseBooleanSchemaElement(char elementId) {
booleanArgs.put(elementId, false);
}
...
private void setBooleanArg(char argChar, boolean value) {
booleanArgs.put(argChar, value);
}
...
public boolean getBoolean(char arg) {
return falseIfNull(booleanArgs.get(arg));
}
}
// TO-BE
public class Args {
private Map<Character, ArgumentMarshaler> boolean booleanArgs = new HashMap<Character, ArgumentMarshaler>();
...
private void parseBooleanSchemaElement(char elementId) {
booleanArgs.put(elementId, new BooleanArgumentMarshaler());
}
...
private void setBooleanArg(char argChar, boolean value) {
booleanArgs.get(argChar).setBoolean(value);
}
...
public boolean getBoolean(char arg) {
Args.ArgumentMarshaler am = booleanArgs.get(arg);
return am != null && am.getBoolean();
}
}
String ์ธ์
์ฒ์ Bool์ด ํต๊ณผํ๋ค๋ฉด String ์ฒ๋ฆฌ๋ ๊ฐ๋จํ๋ค. ์ ์ฌํ๊ฒ ์ฒ๋ฆฌํด์ฃผ๋ฉด ๋๋ค. parse~
, set~
, get~
ํจ์๋ฅผ ์๋ก ๋ง๋ ArguementMarshaler
๋ฅผ ๊ตฌํํ StringArguementMarshaler
๋ก ํ์ฒดํ์.
์ด๋ ๊ฒ ์ ์ฌํ ๋ถ๋ถ์ ์ฐพ์์ ๊ตฌํ์ ์๋ฃํ๋ค๋ฉด ๋ค์ ๋ฌธ์ ๋ Exception์ด๋ค. Exception์ ์ ๋ง ๊ผด๋ดฌ๊ธฐ ์ซ์ ์ฝ๋์ด๋ค. ์ ์ดํด๋ณด๋ฉด, Exception ์ฝ๋๋ Args์ ์ํ์ง ์๋ ์ฝ๋์ด๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ด ๋ชจ๋ ์์ธ๋ฅผ ํ๋ฐ๋ก ๋ชจ์ Args ๋ชจ๋๊ณผ ์๋ฒฝํ๊ฒ ๋ถ๋ฆฌ์ํค์. ์ด๋ ๊ฒ ํด์ ์์ ์ฝ๋๊ฐ ๋์ค๊ฒ ๋์๋ค.
๊ฒฐ๋ก
๊ทธ์ ๋์๊ฐ๋ ์ฝ๋๋ง์ผ๋ก๋ ๋ถ์กฑํ๋ค. ๋จ์ํ ๋์๊ฐ๋ ์ฝ๋์ ๋ง์กฑํ๋ ํ๋ก๊ทธ๋๋จธ๋ ์ ๋ฌธ๊ฐ ์ ์ ์ด ๋ถ์กฑํ๋ค. ๋์ ์ฝ๋๋งํผ ์ง๋ฐฐ์ ์ผ๋ก ๊ฐ๋ฐ ํ๋ก์ ํธ์ ์ ์ํฅ์ ๋ฏธ์น๋ ์์ธ๋ ์๋ค. ๋์ ์ผ์ ์ ๋ค์ ์ง๋ฉด ๋๋ค. ๋์ ์๊ตฌ์ฌํญ์ ๋ค์ ์ ์ํ๋ฉด ๋๋ค. ๋์ ํ ์ญํ์ ๋ณต๊ตฌํ๋ฉด ๋๋ค. ํ์ง๋ง ๋์ ์ฝ๋๋ ์ฉ์ด ๋ฌธ๋๋ฌ์ง๋ค. ์ ์ ๋ฌด๊ฒ๊ฐ ๋์ด๊ฐ ๋ฐ๋ชฉ์ ์ก๋๋ค.
์ฝ๋๋ ์ ๋ฆฌํ ์๋ ์๋ค. ํ์ง๋ง ๋น์ฉ์ด ํฌ๋ค. ์ค๋๋ ์์กด์ฑ์ ๊นจ๊ธฐ ์ํด์๋ ์๋นํ ์๊ฐ๊ณผ ์ธ๋ด์ฌ์ด ๋ ๋ค. ๋ฐ๋ฉด ์ฒ์๋ถํฐ ๊นจ๋ํ ์ํ๋ก ์ ์งํ๋ ค๋ ์ต๊ด์ ๊ฐ๋๋ค๋ฉด ์ด๋ ต์ง ์๋ค. ์ธ์ ๋ ์ฝ๋๋ ์ต๋ํ ๊น๋ํ๊ณ ๋จ์ํ๊ฒ ์ ๋ฆฌํ์.