Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
338 views
in Technique[技术] by (71.8m points)

builder - How to write a overriding method which returns the instace of the calling class in Java

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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> {

  }

}


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...