使用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时如何避免子类回调?的主要内容,如果未能解决你的问题,请参考以下文章
RxJava/Retrofit - 如何强制用户使用特定的订阅者子类?