所以我倾向于赞成组合而不是继承,我希望这个问题的非继承答案。
当超类中有一些代码需要调用子类中的代码时,似乎存在使用组合的情况。这使得不可扩展的继承层次结构首先破坏了使用组合的目的。这是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);
}
}
正如您在此设计中所看到的,存在一个明显的问题。当子类&#39;调用SeparateAtom()
方法,它执行它自己的一些逻辑,然后将其余的委托给基类,然后基类将调用基类上的BreakBond()
方法,而不是子类。
我可以为此考虑各种解决方案,而且几乎所有解决方案都有相当大的挫折:
SeparateAtom()
方法,子类&#39;一。我不觉得有必要解释为什么复制和粘贴不是最佳做法。另一个选择可能是将循环中的一些额外逻辑打包到额外的方法中,这样它就只是复制的循环。但是仍然会复制对其他方法的调用,并且将内容分解为多个方法可能会破坏封装。例如,如果某些逻辑依赖于SeparateAtom()
的特定上下文,并且如果被不熟悉代码的人在非上下文中调用,则会导致错误的数据呢?IBondBreakDelegate
内调用的BondBreak()
。这与听众方法有类似的问题,因为组合和其他方法的混合使得基类的预期用法不清楚。此外,即使现在有一个实际需要的委托,从而使预期的用法更加清晰,基类现在不再能够自行运行。此外,如果需要使用附加子类扩展层次结构(例如public class MoreRealistiChemistry
等),那么如何通过合成扩展委派行为呢?一般来说,当我致力于某种设计时,我想全心全意地这样做。当然,在现实世界中有很多警告。但我觉得这个必须如此普遍,以至于有人可能知道一个好的解决方法。有什么想法吗?
答案 0 :(得分:1)
(由于我的声誉评分很低,我无法添加评论,但我想指出两件事。)
首先,您的代码将无法编译,因为您的类没有实现接口IChemistry
。
其次,“赞成组合而不是继承”只是一个无意中不加区别地应用的指导原则。您应该考虑解决方案所需的模型,如果面对组合或继承的选择,则更喜欢组合。在这个用例中,继承(更具体地说,专业化)似乎是明智的方法。