Java-在设置子字段之前在super的实例化期间调用抽象方法的问题

问题描述 投票:2回答:1

这是我第一次使用这些论坛,所以我希望这个主题合适并且不要搞砸。这在Java中-我将尝试简化示例以关注主要问题。任何帮助,将不胜感激!

说我有两个类,ParentChild,其中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中捕获此方法。

关于我应该如何实现这一点的任何建议(在实例化期间调用抽象方法)?设计模式或设计变更?在孩子中使用重复呼叫?谢谢:)

java constructor parent abstract super
1个回答
1
投票

如正确说明的那样,如果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;
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.