简体   繁体   中英

How to specify the return type of the method of an abstract class

I found a lot of post on the subject, but couldn't manage to find the solution I was looking for.

So here is the deal:

I have a first abstract class with two subclasses:

public abstract class A {
  public A(args){..}
}
public class B extends A {
  public B(args){
    super(args);
  }
}
public class C extends A{
  public C(args){
    super(args);
  }
}

args is some variables but doesn't change in form. Some other stuff are in the classes, but it doesn't matter here.

Now, I have another abstract class with two subclasses that are builders for B and C. The most part of the builders is the same, so I'd like it to be in the abstract builder

public abstract class Builder {
  public A build(*?*){
    //compute args
    return new *either B or C*(args);
  }
}
public class B_Builder extends Builder {
  public B build(*?*){
    super(*?*);
  }
}
public class C_Builder extends Builder{
  public C build(*?*){
    super(*?*);
  }
}

Once again, the other stuff in the builders doesn't really matter.

My question is how to tell to the Builder abastract class what the return type of build should be through the builders subclass. Knowing that the return type B and C both extends A. I guess I should use some generic stuff, but I can't manage to make it work.

Can anyone help me ?

Thanks a lot !

LD

You can do it with a generic type parameter and an abstract creator method that does the construction while the abstract class does the heavy lifting:

public abstract class Builder<T extends A> {
  public T build(*?*){
    //compute args
    return create(args);
  }

  protected abstract T create(args);
}

public class B_Builder extends Builder<B> {
  @Override
  protected B create(args) {
    return new B(args);
  }
}

public class C_Builder extends Builder<C>{
  @Override
  protected C create(args) {
    return new C(args);
  }
}

Yes you are close enough, generic is the way to go:

A:

public abstract class A <T extends A<?>>{

    public abstract T getObject(Object args);
}

B:

   public class B extends A<B>{

        @Override
        public B getObject(Object args) {
            // TODO Auto-generated method stub
            return null;
        }

    }

C:

public class C extends A<C>{

    @Override
    public C getObject(Object args) {
        // TODO Auto-generated method stub
        return null;
    }


}

Add a template parameter to the super class Builder.

class Builder<T> {
  T build() {}
}

Then when you extend use something like

   class ABuilder extends Builder<A> {
      A build() {}
    }

   class BBuilder extends Builder<B> {
      B build() {}
    }

Full code with a working example in Codiva online compiler IDE .

I will suggest put the same part to a single method, and the create codes of B and C should be in the sub-builders.

public abstract class Builder<T> {
  public abstract T create(args);
  public void build(args){
    //do something here
    return create(args); 
  }
}
public class BBuilder extends Builder<B> {
  @Override
  public B create(int args) {
    return new B(args);
  }
}

You can leave only one builder with a single build method like this:

public class BuilderA {
public static <T extends A> T of(Class<T> type, Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    Constructor<T> constructor = type.getConstructor(arg.getClass());
    return constructor.newInstance(arg);
}
}

This method uses reflection to build an instance with the specified type. It assumes that the same type of parameter is used in the constructor of classes A, B and C. Here is how a call would look like:

    A a1 = BuilderA.of(B.class, 1);        
    A a2 = BuilderA.of(C.class, 2);
    B b = BuilderA.of(B.class, 2);
    C c = BuilderA.of(C.class, 2);

In the above calls, all the classes have a constructor with the type Integer. If you have multiple arguments, you can use varargs as the last parameter and retrieve the classes of the vararg and use them for retrieving the right constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM