본문 바로가기
자바(Java)

클린 코드: 애자일 소프트웨어 장인 정신 - 예제

by SSaMKJ 2014. 4. 4.
클린 코드에 나와있는 예제입니다. 이걸 리펙토링 해야 하는데.... 어렵군요. 

메인 함수
package com.ssamkj.test;

public class ArgsMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		try{
			String[] arrgs = {"-l","f","-p","123123","-d","abcd"};
			Args arg = new Args("l,p#,d*", arrgs);
			boolean logging = arg.getBoolean('l');
			System.out.println("logging = "+logging);
			int port = arg. getInt('p');
			System.out.println("port = "+port);
			String directory = arg.getString('d');
			System.out.println("director = "+directory);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

}

Args.java
package com.ssamkj.test;

import java.text.ParseException;
import java.util.*;

public class Args {
	private String schema;
	private String[] args;
	private boolean valid = true;
	private Set unexpectedArguments = new TreeSet();
	private Map booleanArgs = new HashMap();
	private Map stringArgs = new HashMap();
	private Map intArgs = new HashMap();
	private Set argsFound = new HashSet();
	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.trim().length() > 0) {
				parseSchemaElement(element.trim());
			}
		}
		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();
	}

	public boolean getBoolean(char arg) {
		return falseIfNull(booleanArgs.get(arg));
	}

	private boolean falseIfNull(Boolean b) {
		return b != null && b;
	}

	public String getString(char arg) {
		return blankIfNull(stringArgs.get(arg));
	}

	public int getInt(char arg) {
		return zeroIfNull(intArgs.get(arg));
	}

	private int zeroIfNull(Integer i) {
		return i == null ? 0 : i;
	}

	private String blankIfNull(String s) {
		return s == null ? "" : s;
	}

	public boolean has(char arg) {
		return argsFound.contains(arg);
	}

	public boolean isValid() {
		return valid;
	}

	private class ArgsException extends Exception {
	}

	private class ArgumentMarshaler{
		private boolean booleanValue = false;

		public boolean isBooleanValue() {
			return booleanValue;
		}

		public void setBooleanValue(boolean booleanValue) {
			this.booleanValue = booleanValue;
		}
		
	}
	
}



댓글