Bootstrap

《代码整洁之道》第14章 逐步改进 的代码片段

由于没有纸质书或pdf没有代码,不在编辑器里看代码,实在难看懂。所以跟着写了一遍。代码不完全一样,没有单元测试,不保证没问题。大概可以一用吧。

代码14-9

package com.example.demo.args;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * 代码清单 14-9 一个早期版本代码,只支持Boolean 参数
 */
public class Args149 {
    private String schema;
    private String[] args;
    private boolean valid;
    private Set<Character> unexpectArguments = new TreeSet<>();
    private Map<Character, Boolean> booleanArgs = new HashMap<>();
    private int numberOfArguments = 0;

    public Args149(String schema, String[] args) {
        this.schema = schema;
        this.args = args;
        valid = parse();
    }

    public boolean getBoolean(char arg) {
        return booleanArgs.get(arg);//TODO 校验key是否存在,不存在:给提示(抛错太不友好;了)
    }

    public int cardinality() {
        return numberOfArguments;
    }

    public String usage() {
        if (schema.length() > 0)
            return "-[" + schema + "]";
        else
            return "";
    }

    public String errorMessage() {
        if (unexpectArguments.size() > 0)
            return unexpectArgumentsMessage();
        else
            return "";
    }

    public boolean isValid() {
        return valid;
    }

    private boolean parse() {
        if (schema.length() == 0 && args.length == 0) return true;
        parseSchema();
        parseArguments();
        return unexpectArguments.size() == 0;
    }

    private boolean parseSchema() {
        for (String element : schema.split(",")) {
            parseSchemaElement(element);
        }
        return true;
    }

    private void parseSchemaElement(String element) {
        if (element.length() == 1) {
            parseBooleanSchemaElement(element);
        }
    }


    private void parseBooleanSchemaElement(String element) {
        char c = element.charAt(0);
        if (Character.isLetter(c)) {
            booleanArgs.put(c, false);
        }
    }

    private boolean parseArguments() {
        for (String arg : args)
            parseArgument(arg);
        return true;
    }

    private void parseArgument(String arg) {
        if (arg.startsWith("-")) {
            parseElements(arg);
        }
    }

    private void parseElements(String arg) {
        for (int i = 1; i < arg.length(); i++) {
            parseElement(arg.charAt(i));
        }
    }

    private void parseElement(char argChar) {
        if (isBoolean(argChar)) {
            numberOfArguments++;
            setBooleanArg(argChar, true);
        } else
            unexpectArguments.add(argChar);
    }

    private void setBooleanArg(char argChar, boolean value) {
        booleanArgs.put(argChar, value);
    }

    private boolean isBoolean(char argChar) {
        return booleanArgs.containsKey(argChar);
    }

    private String unexpectArgumentsMessage() {
        StringBuffer message = new StringBuffer("Argument(s) -");
        for (Character c : unexpectArguments) {
            message.append(c);
        }
        message.append("  unexpected.");
        return message.toString();
    }

}

代码14-10

package com.example.demo.args;

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

/**
 * 代码清单 14-10
 */
public class Args1410 {
    private String schema;
    private String[] args;
    private boolean valid = true;
    private Set<Character> unexpectArguments = new TreeSet<>();
    private Map<Character, Boolean> booleanArgs = new HashMap<>();
    private Map<Character, String> stringArgs = new HashMap<>();
    private Set<Character> argsFound = new HashSet<>();
    private int currentArgument;
    private char errorArgument = '\0';

    enum ErrorCode {
        OK, MISSING_STRING
    }

    private ErrorCode errorCode = ErrorCode.OK;

    private int numberOfArguments = 0;


    public Args1410(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();
        parseArguments();
        return valid;
    }

    private boolean parseSchema() throws ParseException {
        for (String element : schema.split(",")) {
            if (element.length() > 0) {
                String trimElement = element.trim();
                parseSchemaElement(trimElement);
            }
        }
        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);
    }

    private void validateSchemaElementId(char elementId) throws ParseException {
        if (!Character.isLetter(elementId)) {
            throw new ParseException("Bad character:" + elementId + "in Args format: " + schema, 0);
        }
    }

    private boolean isBooleanSchemaElement(String elementTail) {
        return elementTail.length() == 0;
    }

    private boolean isStringSchemaElement(String elementTail) {
        return "*".equals(elementTail);
    }

    private void parseBooleanSchemaElement(char elementId) {
        booleanArgs.put(elementId, false);
    }

    private void parseStringSchemaElement(char elementId) {
        stringArgs.put(elementId, "");
    }

    private boolean parseArguments() {
        for (currentArgument = 0; currentArgument < args.length; currentArgument++) {
            String arg = args[currentArgument];
            parseArgument(arg);
        }
        return true;
    }

    private void parseArgument(String arg) {
        if (arg.startsWith("-")) {
            parseElements(arg);
        }
    }

    private void parseElements(String arg) {
        for (int i = 1; i < arg.length(); i++) {
            parseElement(arg.charAt(i));
        }
    }

    private void parseElement(char argChar) {
        if (setArgument(argChar)) {
            argsFound.add(argChar);
        } else {
            unexpectArguments.add(argChar);
            valid = false;
        }
    }

    private boolean setArgument(char argChar) {
        boolean set = true;
        if (isBoolean(argChar))
            setBooleanArg(argChar, true);
        else if (isString(argChar))
            setStringArg(argChar);
        else
            set = false;
        return set;
    }

    private void setBooleanArg(char argChar, boolean value) {
        booleanArgs.put(argChar, value);
    }

    private void setStringArg(char argChar) {
        currentArgument++;
        try {
            stringArgs.put(argChar, args[currentArgument]);
        } catch (ArrayIndexOutOfBoundsException e) {
            valid = false;
            errorArgument = argChar;
            errorCode = ErrorCode.MISSING_STRING;
        }
    }

    private boolean isBoolean(char argChar) {
        return booleanArgs.containsKey(argChar);
    }

    private boolean isString(char argChar) {
        return stringArgs.containsKey(argChar);
    }

    public int cardinality() {
        return argsFound.size();
    }

    public String usage() {
        if (schema.length() > 0)
            return "-[" + schema + "]";
        else
            return "";
    }

    public String errorMessage() throws Exception {
        if (unexpectArguments.size() > 0)
            return unexpectArgumentsMessage();
        else
            switch (errorCode) {
                case MISSING_STRING:
                    return String.format("Could not find string paramenter for -%c.", errorArgument);
                case OK:
                    throw new Exception("TILT: should not get here.");
            }
        return "";

    }

    private String unexpectArgumentsMessage() {
        StringBuffer message = new StringBuffer("Argument(s) -");
        for (Character c : unexpectArguments) {
            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 ? false : b;
    }

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

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

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

    public boolean isValid() {
        return valid;
    }

}

基本上算完成的代码:
Args1411

package com.example.demo.args;

import com.example.demo.args.marshaler.ArgumentMarshaler;
import com.example.demo.args.marshaler.BooleanArgumentMarshaler;
import com.example.demo.args.marshaler.IntegerArgumentMarshaler;
import com.example.demo.args.marshaler.StringArgumentMarshaler;

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

public class Args1411 {
    private String schema;
    private List<String> argsList;
    private boolean valid = true;
    private Set<Character> unexpectArguments = new TreeSet<>();
    private Map<Character, ArgumentMarshaler> argumentMarshaler = new HashMap<>();
    private Set<Character> argsFound = new HashSet<>();
    private Iterator<String> currentArgument;
    private ArgsException.ErrorCode errorCode = ArgsException.ErrorCode.OK;


    public Args1411(String schema, String[] args) throws ParseException {
        this.schema = schema;
        this.argsList = Arrays.asList(args);
        valid = parse();
    }

    private boolean parse() throws ParseException {
        if (schema.length() == 0 && argsList.size() == 0) return true;
        parseSchema();
        parseArguments();
        return valid;
    }

    private boolean parseSchema() throws ParseException {
        for (String element : schema.split(",")) {
            if (element.length() > 0) {
                String trimElement = element.trim();
                parseSchemaElement(trimElement);
            }
        }
        return true;
    }

    private void parseSchemaElement(String element) throws ParseException {
        char elementId = element.charAt(0);
        String elementTail = element.substring(1);
        validateSchemaElementId(elementId);
        if (elementTail.length() == 0)
            argumentMarshaler.put(elementId, new BooleanArgumentMarshaler());
        else if ("*".equals(elementTail))
            argumentMarshaler.put(elementId, new StringArgumentMarshaler());
        else if ("#".equals(elementTail))
            argumentMarshaler.put(elementId, new IntegerArgumentMarshaler());

    }

    private void validateSchemaElementId(char elementId) throws ParseException {
        if (!Character.isLetter(elementId)) {
            throw new ParseException("Bad character:" + elementId + "in Args format: " + schema, 0);
        }
    }

    private boolean parseArguments() {
        for (currentArgument = argsList.iterator(); currentArgument.hasNext(); ) {
            String arg = currentArgument.next();
            parseArgument(arg);
        }
        return true;
    }

    private void parseArgument(String arg) {
        if (arg.startsWith("-")) {
            parseElements(arg);
        }
    }

    private void parseElements(String arg) {
        for (int i = 1; i < arg.length(); i++) {
            parseElement(arg.charAt(i));
        }
    }

    private void parseElement(char argChar) {
        if (setArgument(argChar)) {
            argsFound.add(argChar);
        } else {
            unexpectArguments.add(argChar);
            valid = false;
        }
    }

    private boolean setArgument(char argChar) {
        boolean set = true;
        ArgumentMarshaler marshaler = this.argumentMarshaler.get(argChar);
        if (marshaler == null) return false;
        try {
            marshaler.set(currentArgument);
        } catch (ArgsException e) {
            errorCode = e.getErrorCode();
            valid = false;
        }
        return set;
    }

    public int cardinality() {
        return argsFound.size();
    }

    public String usage() {
        if (schema.length() > 0)
            return "-[" + schema + "]";
        else
            return "";
    }

    public String errorMessage() throws Exception {
        if (unexpectArguments.size() > 0)
            return unexpectArgumentsMessage();
        else
            switch (errorCode) {
                case MISSING_STRING:
                    return "Could not find string paramenter for -%c.";
                //其他的省略
                case OK:
                    throw new Exception("TILT: should not get here.");
            }
        return "";

    }

    private String unexpectArgumentsMessage() {
        StringBuffer message = new StringBuffer("Argument(s) -");
        for (Character c : unexpectArguments) {
            message.append(c);
        }
        message.append("  unexpected.");
        return message.toString();
    }

    public boolean getBoolean(char arg) {
        ArgumentMarshaler am = argumentMarshaler.get(arg);
        boolean b;
        try {
            b = am != null && (boolean) am.get();
        } catch (ClassCastException e) {
            b = false;
        }
        return b;
    }


    public String getString(char arg) {
        ArgumentMarshaler am = argumentMarshaler.get(arg);
        return am == null ? "" : (String) am.get();
    }

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

    public Integer getInteger(char arg) {
        ArgumentMarshaler am = argumentMarshaler.get(arg);
        return am == null ? 0 : (Integer) am.get();
    }

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

    public boolean isValid() {
        return valid;
    }
}

ArgumentMarshaler

package com.example.demo.args.marshaler;

import com.example.demo.args.ArgsException;

import java.util.Iterator;

public abstract class ArgumentMarshaler {

    public abstract void set(Iterator<String> integerValue) throws ArgsException;

    public abstract Object get();
}

BooleanArgumentMarshaler

package com.example.demo.args.marshaler;

import java.util.Iterator;

public class BooleanArgumentMarshaler extends ArgumentMarshaler {

    private boolean booleanValue = false;

    public void set(Iterator<String> currentArgument) {
        booleanValue = true;
    }

    public Object get() {
        return booleanValue;
    }
}

IntegerArgumentMarshaler

package com.example.demo.args.marshaler;

import com.example.demo.args.ArgsException;

import java.util.Iterator;

public class IntegerArgumentMarshaler extends ArgumentMarshaler {
    private Integer integerValue;

    public void set(Iterator<String> currentArgument) throws ArgsException {
        try {
            this.integerValue = Integer.valueOf(currentArgument.next());
        } catch (NumberFormatException e) {
            throw new ArgsException(ArgsException.ErrorCode.INALID_INTEGER);
        }
    }

    public Object get() {
        return integerValue == null ? 0 : integerValue;
    }
}

StringArgumentMarshaler

package com.example.demo.args.marshaler;

import com.example.demo.args.ArgsException;

import java.util.Iterator;

public class StringArgumentMarshaler extends ArgumentMarshaler {
    private String stringValue;

    public void set(Iterator<String> currentArgument) throws ArgsException {
        try {
            this.stringValue = currentArgument.next();
        } catch (ArrayIndexOutOfBoundsException e) {
            throw new ArgsException(ArgsException.ErrorCode.MISSING_STRING);
        } catch (ClassCastException e) {
            throw new ArgsException(ArgsException.ErrorCode.INALID_STRING);
        }
    }

    public String get() {
        return stringValue == null ? "" : stringValue;
    }
}

ArgsException

package com.example.demo.args;

public class ArgsException extends Exception {
    private char errorArgument = '\0';
    private String errorParameter = "TILT";

    private ErrorCode errorCode = ErrorCode.OK;

    public ErrorCode getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(ErrorCode errorCode) {
        this.errorCode = errorCode;
    }

    public ArgsException() {
    }

    public ArgsException(String message) {
        super(message);
    }

    public ArgsException(ErrorCode errorCode) {
        this.errorCode = errorCode;
    }

    public enum ErrorCode {
        OK, MISSING_STRING, MISSING_INTEGER,
        INALID_INTEGER, INALID_STRING, UNEXPECTED_ARGUMENT;

    }
}

Args1410Test

package com.example.demo.args;

import java.text.ParseException;

/**
 * description
 *
 * @author lilei
 * @date 2022/4/12 16:32
 */
public class Args1410Test {
    public static void main(String[] args) throws Exception {
        Args1410 args1410 = null;
        String[] args2 = new String[]{"-b", "-s", "A", "-S", "B", "c"};
        try {
            args1410 = new Args1410("b,s*,S*", args2);
        } catch (ParseException e) {
            System.out.println(e.getMessage());
        }
        System.out.printf("usage:%s", args1410.usage());
        System.out.println();
        System.out.printf("boolean:%b", args1410.getBoolean('b'));
        System.out.println();
        System.out.printf("String:%s", args1410.getString('s'));
        System.out.println();
        System.out.printf("String:%s", args1410.getString('S'));
        System.out.println();
        System.out.printf("isValid:%s", args1410.isValid());
        System.out.println();
        System.out.printf("errorMessage:%s", args1410.errorMessage());
    }
}

;