views:

57

answers:

4

I have an abstract base class T, from which classes A and B inherit. I now have an operation (on T) which requires a slightly different implementation in A and B, but most of the code is the same. Let me give you an example: There are two possibilities to implement something like a .Clone method:

Public MustInherit Class T
    Protected MustInherit Function _DoClone() As T

    Public Function Clone() As T
        Dim clone = Me._DoClone()    ' do the subclass-specific stuff '
        ... ' do the shared stuff '
    End Function
End Class

Public Class A
    Inherits T

    Protected Overrides Function _DoClone() As T
        ... ' do the subclass-specific stuff '
    End Function
End Class

or

Public MustInherit Class T
    Protected Sub _DoClone(clone As T)
        ... ' do the shared stuff '
    End Function

    Public MustInherit Function Clone() As T
End Class

Public Class A
    Inherits T

    Public Overrides Function Clone() As T
        Dim clone = ... ' do the subclass-specific stuff '
        Me._DoClone(clone)
    End Function
End Class

(The example is in VB.NET, but the same question applies to C#, Java, etc.)

My questions:

  • Is there an option which is clearly preferred?
  • Is this a well-known pattern that has a name (so that I can do more research)?
  • Are there well-established naming conventions for situations like this (i.e. for the _Do... thing)?
+7  A: 

Looks like Template method pattern:

The template method is used to:

  • let subclasses implement (through method overriding) behavior that can vary
  • avoid duplication in the code: you look for the general code in the algorithm, and implement the variants in the subclasses
  • control at what point(s) subclassing is allowed.
Anton Gogolev
+2  A: 

If the code in the base class is required for the cloning to work, the first option is the correct one. The second option allows you to implement the Clone method without calling the code in the base class.

If the code in the base class is not required, the second option is the correct one. The first option doesn't let you implement a Clone method without calling the code in the base class.

Guffa
+1  A: 

In general I'd use the first approach, since it is simpler. However, in certain cases the second is required.

Note that taking object cloning as example is maybe not optimal. Cloning is special in that the returned object has to be of the same type as the object to be cloned, even though the overridden method is of the base type.

So assume you have a class B which inherits from A, and you do this:

A a = new B();
B b = (B)a.Clone();

Using the first approach, the cloned object has to be created by A, but the type has to be of type B. Typically you'll use object.MemberwiseClone() to achieve that, but this prevents you from replacing readonly fields since that can only be done in the constructor (for instance cloning a List which must not be shared by the clone and the original object).

Lucero
+1  A: 

The first option is fair enough where there is a specific job that you know will be different across derived classes. Perhaps you want to have

Public MustInherit Class T
    Protected MustInherit Function Clone() As T

    Public Function CloneAdjusted() As T
        Dim clone = Me.DoClone()
        ' Adjust clone '
    End Function
End Class

Public Class A
    Inherits T

    Protected Overrides Function Clone() As T
        ' Make exact copy of A '
    End Function
End Class

The second approach would be more appropriate if you're just looking to Clone any old T but want to make small adjustments in the subclasses. But in this case, override the Clone method rather than creating a new one with a new name. For example

Public MustInherit Class T
    Public Overridable Function Clone() As T
        Dim clone = ' Clone a T here '
    End Function
End Class

Public Class A
    Inherits T

    Public Overrides Function Clone() As T
        ' Any pre-clone work '
        T obj = MyBase.Clone()
        ' Any post-clone work '
    End Function
End Class

And no, this doesn't make entirely good sense for a Clone, when you look at it, because you're going to get a T back from the base Clone, and converting that to an A isn't all that easy.

There are a couple of other options you could consider.

One is a helper class. Rather than having any code in T, you might want to move your common code out into a static method of a static class to avoid duplication.

Another is having an ICloner interface which T understands the contract for but A and B understand the implementation, such as

Public MustInherit Class T
    Protected ICloner Cloner

    Public Overridable Function Clone() As T
        ' Common Code '
        Dim clone = Cloner.GetClone()
        ' More Common Code '
    End Function
End Class

Public Class A Inherits T
    Public Sub New()
        Cloner = New ACloner(Me)
    End Sub
End Class

Confused enough yet?

pdr