designing virtual methods
I wonder under what circumstances you would choose the first or the second design :
First design : the child method have to call the base method
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(); }
}
Second design : a virtual method is used to be sure the child do not forget to call the base
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 st开发者_如何转开发uffs */ }
override void OnDisable() { /* do stuffs */ }
}
Thanks
It depends if you really want to make sure IsEnable
gets set or not. If you can imagine scenarios in which the user doesn't want to set it, then I suppose you leave it up to them to call the base method. Otherwise, do it for them.
The second, template-based approach is better in my opinion. It allows you to ensure that some base functionality is always called, and gives you room to add some if none is present at first without the risk of breaking any subclass.
As soon as you make a method virtual, you are giving a derived class a chance to break your class. A responsible deriver will always ask himself "should I call the base implementation?" Guidance for this should always come from documentation. MSDN uses standard verbiage:
Notes to Inheritors:
When overriding Xxxxx in a derived class, be sure to call the base class's Xxxx method so that blablah happens.
The C# language makes that easy with the "base" keyword. Working from the assumption that this documentation is not available or unclear, your second example would strongly discourage a deriver to call the other base class method. After all, s/he wouldn't use the standard pattern. Use this pattern only if you want to discourage the inheritor from calling a base class method.
In the first one, where the overring class could prevent Enable from being set, I reckon Enable and Disable could potentially be misleading method names.
Something like TryEnable and TryDisable would probably be more accurate implying that there are situations where you cannot enable.
A third possible situation could be catered for if you took example 2 and changed it so the base class calls OnEnable before setting the flag:
public void Enable()
{
OnEnable(); // Exceptions raised from here prevent the flag being set.
IsEnable = true;
}
Then overriding classes could prevent the setting of the flag by raising an exception if an error were to occur. Thus error situations would prevent the flag from being changed.
Just food for thought.
精彩评论