我正在尝试使用基于继承的多态和动态绑定来解决设计问题。我有一个抽象的超类和两个子类。超类包含常见行为。 SubClassA和SubClassB定义了一些不同的方法: SubClassA定义了一个方法performTransform(),但SubClassB没有。
以下示例
1 var v:SuperClass;
2 var b:SubClassB = new SubClassB();
3 v = b;
4 v.performTransform();
会在第4行导致编译错误,因为在超类中没有定义performTransform()。我们可以通过转换来编译它......
(v as SubClassA).performTransform();
然而,这将导致抛出运行时异常,因为v实际上是SubClassB的一个实例,它也没有定义performTransform()
所以我们可以通过在投射之前测试对象的类型来解决这个问题:
if( typeof v == SubClassA)
{
(cast v to SubClassA).performTransform();
}
这将确保我们只在作为SubClassA实例的v上调用performTransform()。这对我的眼睛来说是一个非常不优雅的解决方案,但至少它是安全的。我使用了基于接口的多态(接口意义 一种不能的 实例化并定义了实现它的类的API),但这也感觉很笨拙。对于上述情况,如果SubClassA和SubClassB实现了ISuperClass 定义了performTransform,然后他们都必须实现performTransform()。如果SubClassB不需要performTransform(),则必须实现一个空函数。
必须有一个解决问题的设计模式。
答案 0 :(得分:4)
我的直接评论是你的对象建模是错误的。为什么将SubClassA
视为SuperClass
(是-a 关系),当我建议它不时。
你可以实现一个虚拟performTransform()
,它在其基本实例中绝对没有任何内容,并在SubClassA
中被覆盖。但我仍然担心,一方面你将所有这些对象(SubClassA
,SubClassB
)视为同一个东西,然后根据它们的实际实现而不同地对待它们,而不是他们提出的界面。
答案 1 :(得分:3)
假设您使用的是强类型语言,您的问题似乎表明......
没有设计模式可以解决这个问题,因为这是预期的行为。
在您的定义中,performTransform
仅属于SubClassA
。因此,为了能够在对象上调用performTransform
,该对象必须是SubClassA
类型(或SubClassA
的子类型。
在performTransform
上调用SuperClass
没有意义,因为SuperClass
的每个实例都没有定义此方法。
如果实例不是SuperClass
,那么从SubClassA
向SubClassA
的向下投射肯定会引发错误 - 这应该是显而易见的。
因此,您必须更改定义,以使performTransform
属于SuperClass
(在这种情况下,正如您所说,类型SuperClass
的每个实例都需要有一些实现方法,即使是空的方法)或者你必须确保你只是在定义它们的类型上调用方法。
答案 2 :(得分:1)
我不太确定它需要一个模式来解决,而只是一个小的重新设计。如果调用performTransform
的任何内容都有意义,那么它应该在超类中作为虚方法并在子类中重写。
因此,超类从抽象的角度定义流,子类适当地实现它们。在您的情况下,最简单的选择是在超类中保留performTransform
为空,或者将其作为子类中的空方法实现,而不需要它(当您将此方法与简短注释混合时,您得到一个更易维护的系统IMO)。
我能想到的最接近的模式是Null Object模式,其中performTransform
方法只是一个虚函数,用于保持兼容性但不执行实际任务。
答案 3 :(得分:1)
仅仅因为你说你的自行车是一辆汽车并不意味着有一个地方可以放入汽油。多态性的全部意义在于让你把事物看成是超级类 - 这些都是银行账户,这些都是形状,使用经典的例子 - 而不是被它们真正的东西所吸引。有时子类会增加功能。在许多情况下,该功能在每个子类的特定实现中使用。因此,要使用您的姓名,Adjust()
和SuperClass
中的SubClassA
签名中的某个方法SubClassB
已实现(以不同方式)。 SubClassA
版本称自己的performTransform
为过程的一部分,我们都过着幸福的生活。在某些代码需要决定是否调用performTransform
时,您不再只是将其视为SuperClass
。这不一定是需要解决的问题,而是正是这样。
答案 4 :(得分:0)
最好在一个只接受类型SubClassB作为参数的方法中调用performTransform() - 至少你不必进行类型检查。
在说这个问题时,如果你有这个问题可能表明继承可能不是最好的解决方案 - 组合可能是解决问题的更好方法。