【问题标题】:Calling a method AFTER the last constructor ends在最后一个构造函数结束后调用方法
【发布时间】:2014-11-02 22:51:09
【问题描述】:

我有一个问题,可能是不可能的,但值得一试。

我有这些课程:

Class A {
    private int x = 0;

    public A() {
        afterCreate();
    }

    public void afterCreate() {
        x = 10;
    }

    public int getX() { 
        return x; 
    }
}

Class B extends A {
    public B() {
        super();
        //Do something
        afterCreate();
    }

    @Override
    public void afterCreate() {
        x = 20;
    }
}

Class C extends B {
    public C() {
        super();
        //Do something
        afterCreate();
    }

    @Override
    public void afterCreate() {
        x = 30;
    }
}

如您所见,我需要始终在构造函数结束时自动调用afterCreate()。但是如果我只是在每个构造函数中调用afterCreate(),您可以看到对于从类C 创建的对象,我们将调用方法afterCreate() 三次(每个构造函数一次)——前两次调用是没用。

另外,我不能只在第一个构造函数中调用afterCreate(),因为afterCreate() 必须在最后一个构造函数之后执行。

Class A {
    public A() {
        //Do something
        afterCreate();
    }
}

Class B extends A {
    public B() {
        super();
        //Doing something that I missed to process in afterCreate()!
    }
}

Class C extends B {
    public C() {
        super();
        //Doing something that I missed to process in afterCreate()!
    }
}

显然,我不能在 C 类的构造函数中调用afterCreate(),因为如果我从 A 类或 B 类创建对象,则不会调用该方法。

有没有办法在 LAST 构造函数结束时自动调用afterCreate()?

现在想想这个问题,也许如果我能检测到构造函数在超类中被调用,我可以检测到我是否可以调用该方法。

Class A {
    public A() {
        //Do something
        if(thisIsNotCalledAsASuperClass()) afterCreate();
    }
}

Class B extends A {
    public B() {
        super();
        //Do something
        if(thisIsNotCalledAsASuperClass()) afterCreate();
    }
}

Class C extends B {
    public C() {
        super();
        //Do something
        if(thisIsNotCalledAsASuperClass()) afterCreate();
    }
}

//Class D extends C {
//etc.

我不知道....你怎么看?

【问题讨论】:

  • 您这样做是为了达到什么目的?正如您所描述的,afterCreate() 似乎只是一种分解构造函数应该自己做的事情的方法。
  • 这可能不是一个好主意:stackoverflow.com/a/7223444/829571
  • 从构造函数调用可覆盖的方法是非常糟糕的做法,会导致奇怪的行为。超类不应该关心其子类的状态。只是关于它自己的状态。在您的示例中,x 是私有的,因此子类无法访问它。如果x是A的私有字段,必须由A的子类初始化,那么x应该是A的构造函数的参数。
  • @J0e3gan 好吧, afterCreate() 将类似于“抽象”方法。我正在尝试使用它进行排序,但我认为您是对的...
  • @JBNizet 已修复。 x 属性受到保护,但你也有理由。当我评论彼得的答案时,我会再次考虑设计。谢谢!

标签: java constructor


【解决方案1】:

这是个坏主意。构造函数调用基于子类改变行为的方法通常被认为是一种反模式。

如果你真的需要这个功能,我建议在每个类上使用工厂方法并防止直接访问构造函数。问题是您正在为未完全初始化的实例调用可覆盖的方法。

Class A {
    private A() {
        //Do something
    }
    public static A newA() {
        A a = new A();
        a.afterCreate();
        return a;
    }
}

Class B extends A {
    private B() {
        super();
    }
    public static B newB() {
        B b = new B();
        b.afterCreate();
        return b;
    }
}

Class C extends B {
    private C() {
        super();
        //Do something
    }
    public static C newC() {
        C c = new C();
        c.afterCreate();
        return c;
    }
}

【讨论】:

  • 哦,这是一个解决方案,但我会听从你的建议,我不会尝试做这样的事情。我将再次审查设计,以确保我需要以这种方式进行。谢谢!
猜你喜欢
  • 2022-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-20
  • 2016-07-26
  • 2021-11-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多