2012-05-09 5 views
1

У меня есть абстрактный суперкласс и несколько производных классов.
Я хочу, чтобы создать методтребуется совет по дизайну наследования java

createNew() 

при вызове на производном классе будет создавать новый экземпляр производный с помощью смарт-копии всех его членов.
Все члены, которые важны для создания, относятся к абстрактному классу, поэтому код должен быть одним и тем же.
Могу ли я написать реализацию createNew() в суперклассе?

что-то подобное

SonA sonA2 = sonA1.createNew() 
SonB sonB2 = sonB1.createNew() 

абс суперкласса должен сделать реализацию, потому что код идентичен.
спасибо.

ответ

3

Реализация должна быть разделена между абстрактными и конкретными классами. Вы можете сделать это, используя шаблон метода шаблона:

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(); 
    } 
} 

Вы можете разделить ответственность по-другому, чтобы получить точный тип возвращаемого:

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; 
    } 
} 
+0

это не код на самом деле? Разве вы не должны использовать «extends», а не:? – david99world

+0

@ david99world К сожалению, вы правы - я делал слишком много C# в последнее время. Теперь это исправлено, спасибо! – dasblinkenlight

1

Сделать абстрактным методом, который будет служить обратным вызовом, используемым вашим методом createNew, и реализовать , что метод в каждом подклассе. createNew может быть конкретным, даже final метод обычного суперкласса. Указанный абстрактный метод вернет новый экземпляр соответствующего подкласса.

Альтернативный подход заключается в том, чтобы выяснить, через какой класс был вызван класс createNew, и создать на его основе новый экземпляр.

+0

Обратите внимание, что в примере ОП в 'SonA.createNew() и' SonB. createNew() 'имеют разные типы возврата. – NPE

+0

@aix Не обязательно, это может быть ' createNew()'. Он будет работать в этом конкретном случае использования, но в более сложном выражении он не будет полезен. –

1

Вы можете написать этот код (с помощью отражения: getClass().newInstance(), чтобы получить экземпляр фактического класса вместо класса, в котором этот метод определен), но он имеет некоторые проблемы. Например, что вы собираетесь вернуть из этого метода?

Вы должны вернуть супер-тип, что означает, что вы должны бросать для каждого вызова.

Обычным способом является определение метода copy(), который вы определяете на каждом уровне. Тогда вы можете сделать это:

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 ... 
    } 
} 

Вы также можете прочитать о copy constructors.

1

Одной из возможностей является фактором копирования в отдельный метод, и называют, что из производных классов 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; 
    } 
} 
Смежные вопросы