WCW*_*din 9 c# inheritance constructor virtual-functions
我在库中有一个抽象类.我正在尝试尽可能简单地正确实现此类的派生.问题是我需要在三个步骤中初始化对象:获取文件,执行一些中间步骤,然后使用该文件.第一步和最后一步特别适用于派生类.这是一个精简的例子.
abstract class Base
{
// grabs a resource file specified by the implementing class
protected abstract void InitilaizationStep1();
// performs some simple-but-subtle boilerplate stuff
private void InitilaizationStep2() { return; }
// works with the resource file
protected abstract void InitilaizationStep3();
protected Base()
{
InitilaizationStep1();
InitilaizationStep2();
InitilaizationStep3();
}
}
Run Code Online (Sandbox Code Playgroud)
当然,麻烦在于构造函数中的虚方法调用.如果他们不能指望派生类完全初始化,我担心库的使用者在使用类时会发现自己受到限制.
我可以将构造函数中的逻辑拉出到受保护的Initialize()方法中,但是实现者可以直接调用Step1()而Step3()不是调用Initialize().问题的关键在于如果Step2()被跳过则不会有明显的错误; 在某些情况下表现糟糕.
我觉得无论哪种方式都存在严重且不明显的"问题",未来的图书馆用户将不得不解决这些问题.我应该使用其他一些设计来实现这种初始化吗?
如有必要,我可以提供更多细节; 我只是想提供表达问题的最简单的例子.
LBu*_*kin 10
我会考虑创建一个抽象工厂,负责使用模板方法初始化实例化和初始化派生类的实例.
举个例子:
public abstract class Widget
{
protected abstract void InitializeStep1();
protected abstract void InitializeStep2();
protected abstract void InitializeStep3();
protected internal void Initialize()
{
InitializeStep1();
InitializeStep2();
InitializeStep3();
}
protected Widget() { }
}
public static class WidgetFactory
{
public static CreateWidget<T>() where T : Widget, new()
{
T newWidget = new T();
newWidget.Initialize();
return newWidget;
}
}
// consumer code...
var someWidget = WidgetFactory.CreateWidget<DerivedWidget>();
Run Code Online (Sandbox Code Playgroud)
这个工厂代码可以得到显着改进 - 特别是如果你愿意使用IoC容器来处理这个责任......
如果您无法控制派生类,则可能无法阻止它们提供可以调用的公共构造函数 - 但至少可以建立消费者可以遵循的使用模式.
并不总是可以阻止您的课程用户自己动手 - 但是,您可以提供基础设施来帮助消费者在熟悉设计时正确使用您的代码.
对于任何类的构造函数来说,这都太多了,更不用说基类了。我建议您将其分解为一个单独的Initialize方法。