How can I build an object using a varying number of command line arguments?

Viewed 124

I use the builder pattern to make an object. The problem is that I have to get arguments from command line. I want to pass one to six arguments and, based on the arguments amount, call the relevant methods.

For example, if I pass 3 args, the program will call first three methods; first four methods for 4 args and so on;

ExampleClass obj = new ExampleClass.Builder()
                .method1(args[0])
                .method2(args[1])
                .method3(args[2])
                .build();

Is it even possible to make it efficiently? The only thing that occurs to me is reflection, but I'm not sure if this is a good idea.

2 Answers

The trick is to break up the chain of method calls into separate statements rather than try to do it all in one statement. Save the intermediate builder objects in a temporary variable and then call build() at the end.

ExampleClass.Builder builder = new ExampleClass.Builder();

if (args.length >= 1) { builder = builder.method1(args[0]); }
if (args.length >= 2) { builder = builder.method2(args[1]); }
if (args.length >= 3) { builder = builder.method3(args[2]); }
if (args.length >= 4) { builder = builder.method4(args[3]); }
if (args.length >= 5) { builder = builder.method5(args[4]); }
if (args.length >= 6) { builder = builder.method6(args[5]); }

ExampleClass obj = builder.build();

You have a queue of methods defined in the order in which they must be executed.

class Builder {
    Queue<Function<String, Builder>> methods 
        = new LinkedList<>(List.of(this::method1, this::method2, this::method3));
}

You have a queue of arguments formed from a raw array.

Queue<String> argsQueue = new LinkedList<>(Arrays.asList(args));

Given that the method query is always longer than the queue of arguments, the algorithm is

Builder builder = new ExampleClass.Builder();
while (!argsQueue.isEmpty()) {
    builder.getMethods().poll().apply(argsQueue.poll());
}
ExampleClass instance = builder.build();

It shouldn't necessarily be queues.

When you add/remove a method, you would need to take care only of methods.

The whole (dummy) example:

class ExampleClass {
    public static void main(String[] args) {
        Queue<String> argsQueue = new LinkedList<>(Arrays.asList(args));

        Builder builder = new ExampleClass.Builder();
        while (!(argsQueue.isEmpty() || builder.getMethods().isEmpty())) {
            builder.getMethods().poll().apply(argsQueue.poll());
        }
        ExampleClass instance = builder.build();
    }

    public static class Builder {

        private final Queue<Function<String, Builder>> methods = new LinkedList<>(List.of(this::method1, this::method2, this::method3));

        public Queue<Function<String, Builder>> getMethods() {
            return methods;
        }

        public Builder method1(String s) {
            System.out.println("method1 " + s);
            return this;
        }

        public Builder method2(String s) {
            System.out.println("method2 " + s);
            return this;
        }

        public Builder method3(String s) {
            System.out.println("method3 " + s);
            return this;
        }

        public ExampleClass build() {
            System.out.println("building...");
            return new ExampleClass();
        }
    }
}
Related