mis*_*tor 1 java oop swing refactoring initialization
我有一个类,其构造函数如下所示:
abstract class BasePanel extends JPanel {
public BasePanel(A a) {
// initializing fields from values passed to ctor
this.a = a;
// initializing gui components
initializeComponents();
setupPanels();
concludeUiSetup();
}
// stuff
}
Run Code Online (Sandbox Code Playgroud)
在构造函数中,首先初始化要使用传递给构造函数的值进行初始化的字段.然后按顺序调用UI设置所需的其他方法.需要在子类中重写其中两个方法,以便针对它们进行UI设置.
现在考虑一个FooPanel扩展的类BasePanel.它在构造函数中需要更多的初始化参数.
class FooPanel extends BasePanel {
public FooPanel(A a, B b) {
super(a);
this.b = b;
}
@Override
public void initializeComponents() {
super.initializeComponents();
// I require b here, but oops, b is not initialized at this point, and so
// this will throw NPE.
someTextField.setText(b.get());
}
// stuff
}
Run Code Online (Sandbox Code Playgroud)
initializeComponents这里需要的方法b,遗憾的是在那时没有初始化.
重构此代码的适当方法是什么,以便:
FooPanel(和其他面板)的代码不会因此更改而变得混乱.任何帮助非常感谢.谢谢.
您不应该从构造函数中调用可覆盖的方法.在这种情况下,您应该做的是定义一个只初始化实例字段的构造函数,并将GUI的初始化放在一个可重写的initialize()方法中,该方法不是从构造函数中调用的.
因此,要构建一个FooPanel,您可以:
FooPanel p = new FooPanel(a, b);
p.initialize();
Run Code Online (Sandbox Code Playgroud)
如果您不强制FooPanel的所有客户端执行此操作,则将构造函数定义为private,并提供工厂方法:
public static FooPanel create(A a, B b) {
FooPanel p = new FooPanel(a, b);
p.initialize();
return p;
}
Run Code Online (Sandbox Code Playgroud)
基本上,尽量避免在构造函数中调用虚拟(即可覆盖)方法.它确实导致了这种问题.如果你要在构造函数中调用虚方法,你需要记录它 - 并且很可能避免在其他任何地方调用它.必须编写这样一种方法来处理尚未完全初始化的对象,这使得它处于一个尴尬的境地.
在没有更多信息的情况下很难知道更具体的建议,但我也鼓励你尽可能地接受组合而不是继承 - 或者至少总是考虑它,并决定最优雅的方法.
如果你真的想要继承这里,你真的需要initializeComponents吗?每个类都不能在自己的构造函数中进行自己的初始化,而不依赖于其子类状态的任何内容吗?