tags:

views:

170

answers:

4

Hello,

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 stuffs */ }
    override void OnDisable() { /* do stuffs */ }
}

Thanks

+4  A: 

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.

mquander
+3  A: 

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.

zneak
+1  A: 

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.

Mongus Pong
+2  A: 

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.

Hans Passant
I agree that adding extensibility points such as virtual methods offers many opportunities for pain, but I'm not sure that I'd characterize that as the brittle base class problem. Normally I think of the brittle base class problem as being a *derived class* being broken by a *change to the base class*.
Eric Lippert
Agreed, after re-reading your blog post. Edited. Thanks.
Hans Passant