我知道从基类构造函数调用虚拟方法可能很危险,因为子类可能未处于有效状态。(至少在C#中)
我的问题是,如果虚拟方法是初始化对象状态的方法,那该怎么办?是好的做法还是应该分两步进行:首先创建对象,然后加载状态?
第一种选择:(使用构造函数初始化状态)
public class BaseObject { public BaseObject(XElement definition) { this.LoadState(definition); } protected abstract LoadState(XElement definition); }
第二种选择:(使用两步过程)
public class BaseObject { public void LoadState(XElement definition) { this.LoadStateCore(definition); } protected abstract LoadStateCore(XElement definition); }
在第一种方法中,代码的使用者可以使用一个语句创建和初始化对象:
// The base class will call the virtual method to load the state. ChildObject o = new ChildObject(definition)
在第二种方法中,使用者必须创建对象,然后加载状态:
ChildObject o = new ChildObject(); o.LoadState(definition);
(此答案适用于C#和Java。我相信C ++在此问题上的工作方式有所不同。)
在构造函数中调用虚拟方法确实很危险,但有时最终会得到最干净的代码。
我会尽量避免在可能的情况,但没有弯曲的设计 巨大 。(例如,“初始化之后”选项禁止不变性。)如果你 做 在构造函数中使用虚拟方法,文件就 非常 强烈。只要每个参与人员都知道它在做什么,就不会引起 太多 问题。但是,正如您在第一个示例中所做的那样,我将尝试限制可见性。
编辑:这里很重要的一件事是C#和Java之间的初始化顺序有所不同。如果您有以下课程:
public class Child : Parent { private int foo = 10; protected override void ShowFoo() { Console.WriteLine(foo); } }
where the Parent constructor calls ShowFoo, in C# it will display 10. The equivalent program in Java would display 0.
Parent
ShowFoo