我想知道在什么情况下你会选择第一种或第二种设计:
首先设计:子方法必须调用基本方法
public abstract class Base
{
public virtual void Enable() { IsEnable = true; }
public virtual void Disable() { IsEnable = false; }
public bool IsEnable { get; private set; }
}
public class Child : Base
{
public override void Enable() { /* do stuffs */ base.Enable(); }
public override void Disable() { /* do stuffs */ base.Disable(); }
}
第二种设计:使用虚拟方法确保孩子不要忘记调用基础
public abstract class Base
{
public void Enable()
{
IsEnable = true;
OnEnable();
}
public void Disable()
{
IsEnable = false;
OnDisable();
}
public bool IsEnable { get; private set; }
public virtual void OnEnable() {}
public virtual void OnDisable() {}
}
public class Child : Base
{
override void OnEnable() { /* do stuffs */ }
override void OnDisable() { /* do stuffs */ }
}
由于
答案 0 :(得分:3)
这取决于您是否确实要确保IsEnable
被设置。如果您可以想象用户不想设置它的场景,那么我想您可以将它留给他们来调用基本方法。否则,为他们做。
答案 1 :(得分:3)
第二,template-based approach在我看来更好。它允许您确保始终调用某些基本功能,并且如果最初没有任何基本功能,则可以添加一些功能,而不会有破坏任何子类的风险。
答案 2 :(得分:2)
只要你创建一个虚拟方法,你就会给派生类一个破坏你的类的机会。负责任的派生者总会问自己“我应该调用基础实现吗?”对此的指导应始终来自文档。 MSDN使用标准措辞:
对继承者的说明:
在派生中覆盖Xxxxx时 上课时,一定要打电话给基地 类的Xxxx方法让blablah 发生的情况。
使用“base”关键字,C#语言可以轻松实现。假设这个文档不可用或不清楚,你的第二个例子强烈反对派生者调用另一个基类方法。毕竟,他/她不会使用标准模式。仅当您希望阻止继承者调用基类方法时才使用此模式。
答案 3 :(得分:1)
在第一个中,覆盖类可以阻止设置Enable,我认为启用和禁用可能会误导方法名称。
像TryEnable和TryDisable这样的东西可能更准确,暗示有些情况下你无法启用。
第三种可能的情况可以照顾,如果您使用示例2并更改它,以便基类在设置标志之前调用OnEnable:
public void Enable()
{
OnEnable(); // Exceptions raised from here prevent the flag being set.
IsEnable = true;
}
然后,如果发生错误,则重写类可以通过引发异常来阻止设置标志。因此,错误情况会阻止标志被更改。
只是值得深思。