Reputation: 18521
I have an abstract super class and a few derived class.
I want to create a method
createNew()
when invoked on a derived class it will create a new instance of the derived with a smart copy of all of its members.
All the members that are important for the creation are in the abstract class so the code should be the same.
can I write the implementation of createNew() in the super class?
something like that
SonA sonA2 = sonA1.createNew()
SonB sonB2 = sonB1.createNew()
the abs superclass should do the implementation because the code is identical .
thanks.
Upvotes: 1
Views: 137
Reputation: 726579
The implementation should be split between the abstract and the concrete classes. You can do it using the Template Method pattern:
public abstract class AbstractSon {
protected abstract AbstractSon createNewImpl();
public AbstractSon createNew() {
AbstractSon res = createNewImpl();
res.name = "default name";
return res;
}
}
public class Son1 extends AbstractSon {
protected AbstractSon createNewImpl() {
return new Son1();
}
}
public class Son2 extends AbstractSon {
protected AbstractSon createNewImpl() {
return new Son2();
}
}
You can split the responsibility differently to get the precise return type:
public abstract class AbstractSon {
protected void prepare(AbstractSon toPrepare) {
toPrepare.name = "default name";
}
}
public class Son1 extends AbstractSon {
public Son1 createNew() {
Son1 res = new Son1();
prepare(res);
return res;
}
}
public class Son2 extends AbstractSon {
public Son2 createNew() {
Son2 res = new Son2();
prepare(res);
return res;
}
}
Upvotes: 3
Reputation: 500357
One possibility is to factor the copying out into a separate method, and call that from the derived classes' createNew()
:
abstract class Base {
public abstract Base createNew();
protected void populate(Base out) {
// copy the data from `this' to `out'
}
}
class Derived1 extends Base {
public Derived1 createNew() {
Derived1 ret = new new Derived1();
populate(ret);
return ret;
}
}
class Derived1 extends Base {
public Derived2 createNew() {
Derived2 ret = new new Derived2();
populate(ret);
return ret;
}
}
Upvotes: 1
Reputation: 328594
You can write this code (using reflection: getClass().newInstance()
to get an instance of the actual class instead of the class in which the method is defined) but it has some problems. For example what do you intend to return from this method?
You have to return the super type which means you have to cast for every invocation.
The usual solution is to define a copy()
method that you define on every level. Then you can do this:
class SonA {
SonA createNew() {
SonA result = new SonA();
this.copy( result );
return result;
}
void copy( SonA target ) {
super.copy( target );
// copy my fields to target ...
}
}
You may also want to read about copy constructors.
Upvotes: 1
Reputation: 200158
Make an abstract method that will serve as a callback used by your createNew
method -- and implement that method in each subclass. createNew
can be a concrete, even final
method of the common superclass. The mentioned abstract method will return a new instance of the respective subclass.
An alternative approach is to find out through reflection on which class createNew
was called and make a new instance based on that.
Upvotes: 1