dimanche 8 janvier 2017

Design patterns that I could apply on this?

I'm struggling to improve this command-line java application, it reads excel or txt files, besides allow the user do some "querys" with the data loaded. I cant use any external library, so I'm doing it all and now I'm trying to do some refactoring on it, to let it scalable, maybe in the future I could add some new commands / querys. I tried some design patterns like builders, interfaces and etc ..., but it does not seem right. You guys have any tip to abstract this in some elegant way ? I will post the first working version of the application to you guys give it a look:

Reader.java - this class read the file and return a array with all the rows and each row another array in which it will store each attribute of the row:

public class Reader {

public ReaderConfig readerConfig;   

public Reader(ReaderConfig readerConfig){
    this.readerConfig = readerConfig;
}

public List<String[]> read() {
    List<String[]> rows = new ArrayList<String[]>();
    try {
        BufferedReader br = new BufferedReader(new FileReader(readerConfig.getPath()));

        String row = "";
        while ((row = br.readLine()) != null) {
            String[] properties = row.split(readerConfig.getDelimiter());
            rows.add(properties);
        }

        br.close();

    } catch (IOException ex) {
        ex.printStackTrace();
    }

    return rows;
}

}

ReaderConfig.java - It will parameterize Reader.java, based on user input:

public class ReaderConfig {

private String path;
private String delimiter;
private boolean hasHeader;

private Scanner scanner = new Scanner(System.in);

public void setPathFile() {
    System.out.println("Enter the full path of the file (Ex: C:/user/Document/file.csv)");
    String input = scanner.nextLine();
    if(FileUtils.isFileExtensionValid(FileUtils.getFileExtension(input))){
        try {
            new FileReader(input);
            this.path = input;
        } catch (FileNotFoundException e) {
            System.out.println("Invalid file path!!");
            setPathFile();
        }
    }else{
        System.out.println("Invalid extension! Avaliable extension: .txt and .csv");
        setPathFile();
    }
}

public void setDelimiter() {
    System.out.println("Enter the delimiter used by file (Example ;)");
    String input = scanner.nextLine().trim();
    if(input.length() == 0){
        System.out.println("Invalid delimiter!");
        setDelimiter();
    }

    this.delimiter = input;
}

public void setHasHeader() {
    System.out.println("Does the file have header? (Y/N)");
    String input = scanner.nextLine().trim().toUpperCase();

    if(InputUtils.isBooleanInputValid(input)){
        this.hasHeader = InputUtils.evalInputToBoolean(input);
    }else{
        System.out.println("Invalid command!");
        setHasHeader();
    }

}

/** GETTERS */
public String getPath() {
    return path;
}

public String getDelimiter() {
    return delimiter;
}

public boolean hasHeader() {
    return hasHeader;
}

}

And last but not least, the main class that will run the application:

public class Main {

public static void main(String[] args) {        
    ReaderConfig readerConfig = new ReaderConfig();
    readerConfig.setPathFile();
    readerConfig.setDelimiter();
    readerConfig.setHasHeader();

    Reader reader = new Reader(readerConfig);

    System.out.println("Loading file...");
    List<String[]> data = reader.read();
    System.out.println("File loaded...");

    //Header information 
    String[] headers = {};
    if(readerConfig.hasHeader()){
        headers = data.get(0);
        System.out.println("Avaliable headers: " + Arrays.toString(headers));
    }

    //Listen console for commands:
    Scanner scanner = new Scanner(System.in);

     while (true) {
         System.out.println("Enter a command (or QUIT to exit): ");
         String input = scanner.nextLine();

         if(input.toLowerCase().equals("quit")){
             scanner.close();
             System.out.println("Bye.");
             break;

         } else if(input.equals("count *")){
             System.out.println("Total records: " + data.size());

         } else if(input.matches("count distinct \\[(.*?)\\]")){

             int headerIndex = -1;               
             if(headers.length > 0) {
                 headerIndex = Arrays.asList(headers).indexOf(getParameter("count distinct \\[(.*?)\\]", input));
             }else{
                 //If not have a header, check if the column index has been passed as parameter
                 String isNumberRegex = "\\d+";
                 String parameter = getParameter("count distinct \\[(.*?)\\]", input);
                 if(parameter.matches(isNumberRegex)){
                     headerIndex = new Integer(parameter);
                 }
             }
             if(headerIndex != -1){
                 Set<String> set = new HashSet<String>();
                 for(String[] props : data){
                     set.add(props[headerIndex]);
                 }
                 System.out.println("Total records: " + set.size()); 
             }else{
                 System.out.println("Header not found!");
             }

         } else if(input.matches("filter \\[(.*?)\\] \\[(.*?)\\]") && headers.length > 0) {

             int propIndex = Arrays.asList(headers).indexOf(getParameter("filter \\[(.*?)\\] \\[(.*?)\\]", input));
             String value = getValue("filter \\[(.*?)\\] \\[(.*?)\\]", input);
             System.out.println(headers[propIndex]);
             int cont = 0;
             for(String[] test : data){
                 if(Arrays.asList(test).contains(value)){
                     System.out.println(Arrays.toString(test));
                     cont++;
                 }
             }
             System.out.println("Total rows found: " + cont);

         } else if(input.equals("help")){

            System.out.println("Avaliable commands: \n"
                    + " count * - Display the total of rows imported.\n"
                    + " count distinct [header] - Displays the total of distinct rows based on a entered header.\n"
                    + " filter [header] [value] - Display the header and all his rows based in the value entered."
                    + " quit - Quit the application. \n");

         }else{
             System.out.println("Invalid command!");
         }
    }
}  

public static String getParameter(String pattern, String input){
    String header = "";
    Pattern p = Pattern.compile(pattern);
    Matcher m = p.matcher(input);

    while(m.find()) {
        header = m.group(1);
    }

    return header;
}

public static String getValue(String pattern, String input){
    String value = "";
    Pattern p = Pattern.compile(pattern);
    Matcher m = p.matcher(input);

    while(m.find()) {
        value = m.group(2);
    }

    return value;
}

}

Aucun commentaire:

Enregistrer un commentaire