Java-强制子类在构造函数之后调用超级方法
我希望一堆子类在完成构造函数后调用超级方法,如下所示:Java-强制子类在构造函数之后调用超级方法,java,inheritance,constructor,Java,Inheritance,Constructor,我希望一堆子类在完成构造函数后调用超级方法,如下所示: public abstract class Superclass { ... public Superclass(...) { ... // do stuff before initializing subclass } protected void dispatch() { //method to be called directly after creating an
public abstract class Superclass {
...
public Superclass(...) {
... // do stuff before initializing subclass
}
protected void dispatch() { //method to be called directly after creating an object
doStuff();
...
}
public abstract void doStuff();
}
public class Subclass extends Superclass {
...
public Subclass(...) {
super(...); //has to be the first line
... //assign variables etc.
dispatch(); //has to be called after variables are assigned etc.
}
public void doStuff() {
//do stuff with assigned variables etc.
}
}
SuperClass.executeAnActionOnSuperClass(new SubClass(...));
dispatch()
函数包含一组在对象创建后要处理的事情,必须应用于所有子类。我不能将这个函数移到超级构造函数中,因为它调用子类中的方法,这些子类需要已经分配的变量。但是由于super()
需要作为子构造函数的第一行,因此在调用超级构造函数之前,我无法设置任何变量
它将像现在一样工作,但我发现在每个子类的构造函数末尾调用
dispatch()
是一个糟糕的概念。有没有更优雅的方法来解决这个问题?或者我应该完全重新思考我的概念吗?如果调用方法时确实需要完成任何子类实例化,那么LORE是正确的。否则,你可以做你所拥有的。如果其他人需要使用该代码,我建议您提供足够的注释。您的请求违反了一些Java最佳实践,例如:
- 不要在构造函数中进行复杂的配置,只填充私有(最终)成员变量,只执行非常基本的一致性检查(如果有)
- 不要从构造函数调用
或非私有
方法,甚至不要间接调用非最终
静态方法来抽象超类的使用,但也可以检查它是否已正确设置:
public abstract class SuperClass{
private boolean instantiated;
public SuperClass(...){
...
}
public abstract void doStuff();
private void dispatch(){
if(!instantiated){
instantiated = true;
doStuff();
}
}
public static void executeActionOnSuperClass(SuperClass s){
s.dispatch(); // call instantiation if not already done
s.executeAnAction();
}
}
和子类:
public class SubClass extends SuperClass{
public SubClass(...){
super(...);
}
public void doStuff(){
...
}
}
然后可以这样执行:
public abstract class Superclass {
...
public Superclass(...) {
... // do stuff before initializing subclass
}
protected void dispatch() { //method to be called directly after creating an object
doStuff();
...
}
public abstract void doStuff();
}
public class Subclass extends Superclass {
...
public Subclass(...) {
super(...); //has to be the first line
... //assign variables etc.
dispatch(); //has to be called after variables are assigned etc.
}
public void doStuff() {
//do stuff with assigned variables etc.
}
}
SuperClass.executeAnActionOnSuperClass(new SubClass(...));
虽然这主要是一种反模式,应该少用
它会像现在这样工作,但我觉得这是一个糟糕的概念
dispatch()位于每个子类的构造函数末尾。有没有
更优雅的解决方法?或者我应该彻底重新思考我的生活吗
概念
正如Timothy Truckle所强调的,您的构造函数逻辑太复杂了
通过使用template方法初始化子类实例,您可以使事情变得更简单并达到您的目标。
请注意,您已经将此模式用于doStuff()
子类构造函数确实是您的问题:您希望减少每个子类中所需的强制锅炉板,并使其可读性和维护性更好。
因此,在超类中引入一个新的模板方法,并从超类的构造函数中调用它。
此方法将执行与构造函数相同的操作,但可以以更灵活的方式调用。
dispatch()
这是一种人工方法,仅用于技巧,也不需要。
整个逻辑可以通过超类构造函数进行编排
超级类可能看起来像:
public abstract class Superclass {
...
public Superclass(...) {
... // do stuff before initializing subclass
init();
doStuff();
}
public abstract void init();
public abstract void doStuff();
}
在子类中,替换为:
public Subclass(...) {
super(...); //has to be the first line
... //assign variables etc.
dispatch(); //has to be called after variables are assigned etc.
}
作者:
结果要简单得多,因为这种设计将与子类的初始化“算法”相关的责任集中在一个地方:超级类构造函数
关于你的评论:
这看起来确实比我做的要优雅得多。非常感谢。编辑:
刚才注意到,这不适用于具有不同
构造函数参数。你知道怎么解决这个问题吗
有了这样的要求,要使事情变得简单明了,你必须分两步来做:
- 实例化对象
- 在引用上调用
init()
方法李>
它可能看起来像:
SuperClass o = new Subclass(argFoo, argBar);
o.init();
这种方法的问题是您不确定是否调用了init()
方法。您可以添加一个标记,在每次对对象调用方法时检查该标记。但它确实很麻烦,而且容易出错。避免这种情况。
为了改进这一点,我可能会使用包装器模式。
您还可以使用拦截器/方面。但这不是一个好的用例:init处理不是横向的,它实际上与对象行为相关。让它可见更有意义
使用包装器时,它可能看起来像:
SuperClass o = new MyWrapper(new Subclass(argFoo, argBar));
其中,MyWrapper
是SuperClass
的子类,并包装了SuperClass
对象的实例:
public class MyWrapper implements SuperClass{
private SuperClass wrapped;
public MyWrapper (SuperClass wrapped){
this.wrapped = wrapped;
this.wrapped.init();
}
// then delegate each superclass method to the wrapped object
public void doStuff(){
this.wrapped.doStuff();
}
// and so for...
}
你不能,这是个坏主意。如果您使用子类
再次对子类
进行子类化,会怎么样?然后在调用SubSubClass
的构造函数之前调用dispatch
,如果SubSubClass
覆盖了doStuff
,那么该方法将在初始化类之前被调用。这看起来确实比我做的要优雅得多。非常感谢。编辑:刚刚注意到,这不适用于具有不同构造函数参数的子类。你知道如何解决这个问题吗?但这违背了一个事实,即你不能从超类构造函数调用可重写的方法,对吗?@user7 right:这通常是不建议的,但在这里init()
替换了子类的构造函数。因此,在子类实例上调用方法不会有风险,因为子类实例没有调用其构造函数,因此子类实例的状态不一致。