OO模式:抽象基类和子类之间的共享工作

时间:2010-02-26 09:46:48

标签: .net language-agnostic oop

我有一个抽象基类T,其中AB类继承。我现在有一个操作(在T上),需要在AB中稍微不同的实现,但大多数代码是相同的。让我举个例子:有两种方法可以实现.Clone方法:

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

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

(示例在VB.NET中,但同样的问题适用于C#,Java等)

我的问题:

  • 是否有明确首选的选项?
  • 这是一个众所周知的模式,有一个名字(这样我可以做更多的研究)?
  • 对于像这样的情况(即_Do...事物),是否有完善的命名约定?

4 个答案:

答案 0 :(得分:7)

看起来像Template method pattern:

  

模板方法用于:

     
      
  • 让子类实现(通过方法覆盖)可以改变的行为
  •   
  • 避免代码中的重复:您在算法中查找通用代码,并在子类中实现变体
  •   
  • 允许在什么时候控制子类化。
  •   

答案 1 :(得分:2)

如果克隆工作需要基类中的代码,则第一个选项是正确的。第二个选项允许您在不调用基类中的代码的情况下实现Clone方法。

如果不需要基类中的代码,则第二个选项是正确的。第一个选项不允许您在不调用基类中的代码的情况下实现Clone方法。

答案 2 :(得分:1)

一般来说,我会使用第一种方法,因为它更简单。但是,在某些情况下,第二个是必需的。

请注意,以对象克隆为例可能不是最佳选择。克隆的特殊之处在于返回的对象必须与要克隆的对象的类型相同,即使重写的方法属于基类型。

假设您有一个继承自A的B类,您可以这样做:

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

使用第一种方法,克隆对象必须由A创建,但类型必须是B类型。通常,您将使用object.MemberwiseClone()来实现此目的,但这会阻止您替换只读字段因为这只能在构造函数中完成(例如克隆一个不能由克隆和原始对象共享的List)。

答案 3 :(得分:1)

第一个选项是公平的,其中有一个特定的工作,你知道在派生类中会有所不同。也许你想拥有

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

如果您只是想要克隆任何旧的T但想要在子类中进行小的调整,那么第二种方法会更合适。但在这种情况下,请覆盖Clone方法,而不是使用新名称创建新方法。例如

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

不,这对克隆人来说并没有完全合理意义,当你看到它时,因为你将从基础克隆中获得一个T,并将其转换为A并不是全部容易。

您可以考虑其他几种选择。

一个是助手类。您可能希望将公共代码移到静态类的静态方法中,以避免重复,而不是在T中包含任何代码。

另一个是拥有ICloner接口,T了解合同但A和B理解实施,例如

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

足够困惑?