使用Composition时如何避免子类回调?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Composition时如何避免子类回调?相关的知识,希望对你有一定的参考价值。

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

当超类中有一些代码需要调用子类中的代码时,似乎存在使用组合的情况。这使得不可扩展的继承层次结构首先破坏了使用组合的目的。这是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()方法中的循环(和附加逻辑)复制到子类'one。我觉得没有必要解释为什么复制和粘贴不是最好的做法。另一种选择可能是将循环中的一些额外逻辑打包成额外的方法,这样它就是被复制的循环。但是仍然会复制对其他方法的调用,并且将内容分解为多个方法可能会破坏封装。例如,如果某些逻辑依赖于SeparateAtom()and的特定上下文,如果被不熟悉代码的人称为超出上下文,则会导致数据错误?
  • 听取或观察基类中的破坏事件。这个解决方案对我来说似乎有问题,因为基类功能应该扩展的方式变得不清楚。例如,在没有先验知识的情况下,如果有人试图扩展类,他们可能直观地实现上面的设计并将监听器解释为可选的,当事实上如果想要延长键断开行为则需要。
  • 使基类需要委托。例如,基类可能需要引用IBondBreakDelegate内部的BondBreak()。这与听众方法有类似的问题,因为组合和其他方法的混合使得基类的预期用法不清楚。此外,即使现在有一个实际需要的委托,从而使预期的用法更加清晰,基类现在不再能够自行运行。此外,如果需要使用附加子类扩展层次结构(例如public class MoreRealistiChemistry等),那么如何通过合成扩展委派行为?
  • 委托一切而不是作曲。我宁愿不沿着这条路走下去,因为当课程需要额外的功能时,所需的代表数量会增加(或代表中的方法数量会增加)。如果某些委托行为是可选的呢?然后,要么为子类实现的每个行为都需要单独的可选委托,要么最终在子类中有许多空方法体。

一般来说,当我致力于一种设计时,我想全心全意地这样做。当然,在现实世界中有很多警告。但我觉得这个必须如此普遍,以至于有人可能知道一个好的解决方法。有任何想法吗?

以上是关于使用Composition时如何避免子类回调?的主要内容,如果未能解决你的问题,请参考以下文章

以不同方式处理子类/避免代码重复

React JS 如何避免深度回调

RxJava/Retrofit - 如何强制用户使用特定的订阅者子类?

如何让 Vue3 Composition API 代码看起来更函数式?

在超类中使用描述符以避免子类中的代码重复

面试题如何避免使用过多的 if else?