0

I am relatively new to Java and Design patterns. I am trying to implement the Builder pattern for my application. I have an interface which has a method build this build method will take the class as a parameter and return the same.

public interface TestInterface {
    public TestInterface withTest(int start);
    public <T> T build();
}

As of now, I have implemented this interface within a single class and overriding the methods in the GenerateBuilder class and it works fine

public class GenerateNumbers {

private String start;

private GenerateGSRN(GenerateBuilder builder) {
        this.start = builder.start;
    }

    public static class GenerateBuilder implements TestInterface {

        private String start;

        @Override
        public TestInterface withGcp(String start) {
            this.start = start;
            return this;
        }

        @Override
        public GenerateNumbers build() {
            return new GenerateNumbers(this);
        }

    }
}

But I want to move the GenerateBuilder class which is overriding the methods to its own separate class so that it can be used by any other class (make it as common so I do not have to write this code again).

But as we can see the GenerateBuilder Build function is tightly coupled to GenerateNumbers due to which I am unable to move it. I want to change the Build method in Interface as well as during the overriding so that it will return the instance of the class to calling class.

For example: If GenerateNumbers is calling build method then build method should return GenerateNumbers. If GenerateNumbersRandom is calling then build method should return instance of GenerateNumbersRandom.

I tried couple of things but did not work:

In interface: public <T> T build(Class clazz);

In the override:

@Override
        public <T> T build(Class clazz) {
            return clazz.newInstance();
        }

I hope I was able to explain the problem properly. Can someone please suggest me how to make this work.

BATMAN_2008
  • 2,788
  • 3
  • 31
  • 98
  • Just to make sure I understand, you want an instance of a children class to build another instance of the same class by calling a parent's _eventually `final`_ method? – Vincent C. Jan 06 '21 at 15:00
  • Yes, I want the `build` method to return an instance of a child class that is making a call to it. For example in this case, when `GenerateNumbers ` makes a call it should create `GenerateNumbers ` similar to the way I have it now in hard coded value. – BATMAN_2008 Jan 06 '21 at 15:04
  • My main question would be: Why? You want a generic class that can create a generic builder object, which in its turns can generate another generic object. Why do you think you need all this complexity? What underlying problem are you trying to solve? – fishinear Jan 06 '21 at 18:32
  • I have multiple classes that are similar to `GenerateNumbers` but produce different outputs. If I do not create a Generic class then I would end up writing the same code in each and every class but with a different class name. Hence, I would like to create a generic class so that I can use it in all classes and do not have to create this class within all the classes I create. – BATMAN_2008 Jan 06 '21 at 20:46

1 Answers1

0

From what I understand, you could:

  • declare your interface has having generic type (Builder)
  • declare the type you want to be built by the class implementing the interface (NumberGenerator)
  • declare the builder as an implementation of the interface having for generic type the class it will build (NumberGeneratorBuilder implements Builder<NumberGenerator>)
  • in the Builder interface, access to actual type of generic at runtime to instantiate a new instance of this type.

As an example, this would give something like:

import java.lang.reflect.ParameterizedType;

public interface Builder<T> {

  default T build() throws IllegalAccessException, InstantiationException {
    // in a more production-ready application, you would not reference item with their index but lookup through correct criterion to avoid getting a bad class instantiated
    return ((Class<T>) ((ParameterizedType) this.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0]).newInstance();
  }
}
public class NumberGenerator {

  public static NumberGenerator instance() throws InstantiationException, IllegalAccessException {
    return new NumberGeneratorBuilder().build();
  }

  // Note that visibility is important here, default constructor needs to be visible from the Builder class, and not from its implementation
  NumberGenerator() {

  }

  public static class NumberGeneratorBuilder implements Builder<NumberGenerator> {

  }

}

Vincent C.
  • 607
  • 5
  • 18
  • Thanks a lot for taking your time and answering. But I am actually looking for an answer where I have to just modify my `Build` method in `Interface` and in implementation. I do not want to make the changes to the whole interface as it has many other methods that return different forms of data. I just want to know how can the `Build` method take the input as Class and return the instance of the same class to calling class. – BATMAN_2008 Jan 06 '21 at 16:08
  • So you can not add a generic type to your `TestInterface`? – Vincent C. Jan 06 '21 at 16:12
  • Actually, I would not like to make any modifications to `Interface` itself as it has many methods and it has been implemented by many classes. I would like to just make a modification to my `build` method within it and also to the `build` method which has been overridden within the implemented classes. – BATMAN_2008 Jan 07 '21 at 08:01