这是我第一次使用这些论坛,所以我希望这个主题合适并且不要搞砸。这在Java中-我将尝试简化示例以关注主要问题。任何帮助,将不胜感激!
说我有两个类,Parent和Child,其中Parent是一个抽象类,Child扩展了Parent。 (我正在即时编写此代码)...
public abstract class Parent {
// A bunch of fields that have been omitted...
public Parent() {
print(getX());
}
public abstract int getX();
}
public class Child extends Parent {
private int x;
public Child(int x) {
super();
this.x = x;
}
@Override
public int getX() {
return x;
}
}
我想实例化Child,并在实例化后立即调用抽象方法。显然,当前存在一个问题,因为在从super()的父级中调用getX()时,尚未设置x字段,因此将始终返回0。
但是,我希望对Parent的所有子代都在父级中执行此操作(如果将来有扩展了Parent的Child2,Child3等)。即,扩展“父级”的任何内容都将打印其“ x”值。解决该问题的方法是在实例化的每个Child上打印getX(),但是由于某种原因,我似乎不得不在每个Child类中重复执行此操作,而不是在Parent中捕获此方法。
关于我应该如何实现这一点的任何建议(在实例化期间调用抽象方法)?设计模式或设计变更?在孩子中使用重复呼叫?谢谢:)
如正确说明的那样,如果x
字段是从Parent
派生的所有类的一部分,则该字段是Parent
字段。但是有时情况并非如此,然后您希望在父项完全存活之前设置子项字段。
这是实例化顺序中的常见问题,正如您正确指出的那样:
[...]存在问题,因为从super()[...]]的父级中调用getX()时未设置x字段
由于这个原因,这种调用不能在父构造函数中进行。对此有一些通用的方法,其中大多数方法是在实例完全构建后才调用的
init()
方法。
[执行此操作的一种模式(不使用大量依赖注入)是工厂模式。有关详细信息,请参见https://www.tutorialspoint.com/design_pattern/factory_pattern.htm。
工厂模式的设计方式是,实例不仅由构造函数创建,而且最终由工厂返回,工厂将获得用于实例化的值。实例完成后,该工厂可以保证调用init
方法。
abstract class Parent {
// Notice the protected modifier!
protected Parent() {
// field initializations of Parent.
}
protected void init() {
// I replaced print with System.out.println here ot make it compile.
System.out.println(getX());
}
public abstract int getX();
}
abstract class ParentFactory<T extends Parent> {
public abstract T instance();
}
public class Child extends Parent {
private int x;
protected Child(int x) {
super();
this.x = x;
}
@Override
public int getX() {
return x;
}
}
class ChildFactory extends ParentFactory<Child> {
int x = 0;
public void setX(int x) {
this.x = x;
}
@Override
public Child instance() {
Child instance = new Child(x);
instance.init();
return instance;
}
}
@Test
public void test() {
ChildFactory factory = new ChildFactory();
factory.setX(7);
Child child = factory.instance();
System.out.println("And child has x: " + child.x);
}
请注意,这种工厂(有状态工厂)与Builder模式中的Builder非常相似。它的不同之处仅在于它通常可以重复使用,而不是在现场创建。您可以更改此模式,因为ChildFactory
中还有一个显式方法,该方法在ChildFactory的状态字段上采用显式参数:
public Child instance(int x) {
Child instance = new Child(x);
instance.init();
return instance;
}