所以我倾向于支持组合而不是继承,我希望这个问题的非继承答案。
当超类中有一些代码需要调用子类中的代码时,似乎存在使用组合的情况。这使得不可扩展的继承层次结构首先破坏了使用组合的目的。这是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
等),那么如何通过合成扩展委派行为?一般来说,当我致力于一种设计时,我想全心全意地这样做。当然,在现实世界中有很多警告。但我觉得这个必须如此普遍,以至于有人可能知道一个好的解决方法。有任何想法吗?