【问题标题】:How do you avoid subclass call-backs when using Composition?使用 Composition 时如何避免子类回调?
【发布时间】:2018-02-28 02:58:00
【问题描述】:

所以我倾向于组合而不是继承,我希望这个问题的答案不是继承。

当超类中的某些代码需要调用子类中的代码时,似乎存在使用组合的情况。这导致不可扩展的继承层次结构首先破坏了使用组合的目的。下面是 C# 中问题的演示(虽然这是一个通用的 oop 问题):

public interface IChemistry
{
    void SeparateAtom(Atom atom);
    void BreakBond(Bond bond);
}

public class BaseChemistry : IChemistry
{
    public void SeparateAtom(Atom atom)
    {
        //possible extra logic here
        for(int i=0;i < atom.BondCount;i++)
        {
            //maybe extra logic here etc.
            BreakBond(atom.Bonds[i]);
        }
    }

    public void BreakBond(Bond bond)
    {
        //do some bond breaking logic here
    }
}

public class RealisticChemistry : IChemistry
{
    private BaseChemistry base;

    public RealisticChemistry(BaseChemistry base)
    {
        this.base = base;
    }
    public void SeparateAtom(Atom atom)
    {
        //subclass specific logic here perhaps
        base.SeparateAtom(atom);
    }

    public void BreakBond(Bond bond)
    {
        //more subclass specific logic
        base.BreakBond(bond);
    }
}

正如您所看到的,这个设计存在一个明显的问题。当子类的SeparateAtom() 方法被调用时,它会执行一些它自己的逻辑,然后将其余部分委托给基类,然后基类将在基类而不是子类上调用BreakBond() 方法。

对此我可以想到各种解决方案,但几乎所有解决方案都有相当大的挫折:

  • 复制和粘贴。在这种情况下,最糟糕的选择是将基类的SeparateAtom() 方法中的循环(和其他逻辑)简单地复制到子类的方法中。我觉得没有必要解释为什么复制和粘贴不是最佳做法。另一种选择可能是将循环周围的一些额外逻辑打包到额外的方法中,以便它只是被复制的循环。但是对附加方法的调用仍然被复制,并且将事物分解为多个方法可能会破坏封装。例如,如果其中一些逻辑依赖于 SeparateAtom() 的特定上下文,并且如果被不太了解代码的人在上下文之外调用可能导致错误数据怎么办?
  • 收听或观察基类中的键断裂事件。 这个解决方案对我来说似乎有问题,因为应该扩展基类功能的方式变得不清楚。例如,在没有先验知识的情况下,如果要尝试扩展类,他们可能会直观地实现上述设计并将侦听器解释为可选,而实际上如果想要扩展键破坏行为则需要它。
  • 使基类需要委托。例如,基类可能需要对IBondBreakDelegate 的引用,该引用在BondBreak() 内部调用。这与侦听器方法有类似的问题,因为组合和其他方法的混合使得基类的预期用途不清楚。此外,即使现在有一个实际需要的委托,从而使预期用途更加清晰,但基类现在不能再单独运行。此外,如果需要使用额外的子类(例如 public class MoreRealistiChemistry 等)扩展层次结构,如何通过组合扩展委托行为?
  • 委托一切而不是组合。我不想走这条路,因为当类需要额外的功能时,需要的委托数量会增加(或者委托中的方法数量会增加)。另外,如果某些委托行为是可选的怎么办?然后要么需要为子类实现的每个行为单独的可选委托,要么你最终会在子类中得到很多空的方法体。

一般来说,当我致力于某种设计时,我会全心全意地这样做。当然,在现实世界中有很多警告。但我觉得这个问题一定很常见,以至于有人可能知道一个好的解决方法。有什么想法吗?

【问题讨论】:

    标签: oop inheritance delegates event-listener composition


    【解决方案1】:

    (由于声誉不足,我无法添加评论,但我想指出两点。)

    首先,您的代码无法编译,因为类没有实现IChemistry

    其次,“优先组合优于继承”只是一个指导原则,并不意味着盲目地应用。如果解决方案正在考虑的模型需要继承或组合,则应选择组合。

    对于这个特定的问题,继承(或者更确切地说,专业化)是更明智的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-16
      • 2016-06-24
      • 1970-01-01
      相关资源
      最近更新 更多