Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 面向对象设计问题:多态性_Oop_Inheritance_Polymorphism - Fatal编程技术网

Oop 面向对象设计问题:多态性

Oop 面向对象设计问题:多态性,oop,inheritance,polymorphism,Oop,Inheritance,Polymorphism,我正在尝试使用基于继承的多态性和动态绑定来解决一个设计问题。我有一个抽象的超类和两个子类。超类包含常见的行为。子类A和子类B定义了一些不同的方法: 子类a定义了一个方法performTransform,但子类B没有 下面的例子 1 var v:SuperClass; 2 var b:SubClassB = new SubClassB(); 3 v = b; 4 v.performTransform(); 将导致第4行出现编译错误,因为在超类中未定义performTransform。我们可

我正在尝试使用基于继承的多态性和动态绑定来解决一个设计问题。我有一个抽象的超类和两个子类。超类包含常见的行为。子类A和子类B定义了一些不同的方法: 子类a定义了一个方法performTransform,但子类B没有

下面的例子

1 var v:SuperClass;

2 var b:SubClassB = new SubClassB();

3 v = b;

4 v.performTransform();
将导致第4行出现编译错误,因为在超类中未定义performTransform。我们可以通过强制转换来编译它

(v as SubClassA).performTransform();
但是,这将导致抛出运行时异常,因为v实际上是子类B的实例,子类B也没有定义performTransform

因此,我们可以通过在投射对象之前测试对象的类型来解决这一问题:

if( typeof v == SubClassA)
{
  (cast v to SubClassA).performTransform();
}
这将确保我们只对作为子类实例的v调用performTransform。在我看来,这是一个相当不雅观的解决方案,但至少它是安全的。我使用了基于接口的多态性接口含义 一种不能 被实例化并定义过去实现它的类的API,但这也让人感觉很笨拙。对于上述情况,如果子类A和子类B实现了ISuperClass 如果定义了performTransform,那么他们都必须实现performTransform。如果子类B实际上不需要performTransform,则必须实现一个空函数


必须有一种设计模式来解决这个问题

我的直接评论是,您的对象建模是错误的。为什么要将子类视为超类is-a关系,而我认为它不是


您可以实现一个伪performTransform,它在其基本实例中完全不做任何事情,并且在子类中被重写。但我仍然担心的是,一方面,你把所有这些对象都当作子类A,子类B一样对待,然后想根据它们的实际实现而不是它们所呈现的接口来区别对待它们。

我的直接评论是,你的对象建模是错误的。为什么要将子类视为超类is-a关系,而我认为它不是


您可以实现一个伪performTransform,它在其基本实例中完全不做任何事情,并且在子类中被重写。但我仍然担心的是,一方面,您将所有这些对象子类a、子类B视为同一事物,然后希望根据它们的实际实现而不是它们所呈现的接口对它们进行不同的处理。

假设您使用的是强类型语言,您的问题似乎表明

没有设计模式可以解决这个问题,因为这是预期的行为

在您的定义中,performTransform仅属于子类。因此,为了能够在对象上调用performTransform,该对象必须是Subassa类型或Subassa的子类型

在超类上调用performTransform没有意义,因为不是每个超类实例都定义此方法

如果实例不是子类,则从超类向下转换到子类肯定会引发错误-这应该是显而易见的


因此,您必须更改定义,使performTransform属于超类,在这种情况下,正如您所说,超类类型的每个实例都需要对该方法进行一些实现,即使是空的,也必须确保只调用定义它们的类型上的方法。

假设您使用的是强类型语言,您的问题似乎表明

没有设计模式可以解决这个问题,因为这是预期的行为

在您的定义中,performTransform仅属于子类。因此,为了能够在对象上调用performTransform,该对象必须是Subassa类型或Subassa的子类型

在超类上调用performTransform没有意义,因为不是每个超类实例都定义此方法

如果实例不是子类,则从超类向下转换到子类肯定会引发错误-这应该是显而易见的


因此,您必须更改定义,使performTransform属于超类,在这种情况下,正如您所说,超类类型的每个实例都需要对该方法进行一些实现,即使是空的,也必须确保只调用定义它们的类型上的方法。

我不太确定它需要一个模式来解决,而只是一个小的重新设计。如果调用performTransform有意义的话,它应该作为虚拟方法在超类中,并在子类中重写

因此,超类从抽象的角度定义流,子类适当地实现它们。在您的情况下,最简单的选择是在超类中保留performTransform为空,或者在子类中实现它作为一个空方法,在混合时不需要它 这种方法加上一个简短的注释,您将得到一个更易于维护的系统


我能想到的最接近于此的模式是空对象模式,其中performTransform方法只是一个保留兼容性的虚拟函数,但不执行实际任务。

我不太确定它需要一个模式来解决,而只是一个小的重新设计。如果调用performTransform有意义的话,它应该作为虚拟方法在超类中,并在子类中重写

因此,超类从抽象的角度定义流,子类适当地实现它们。在您的情况下,最简单的选择是要么在超类中保留performTransform为空,要么在子类中将其实现为不需要它的空方法。当您将此方法与简短注释混合使用时,您将得到一个更易于维护的系统


我能想到的最接近于此的模式是空对象模式,其中此performTransform方法只是一个保留兼容性但不执行实际任务的伪函数。

最好在一个只将类型子类B作为参数的方法中调用performTransform,至少您不必执行类型转换那就检查一下


一说起来,,如果您有这个问题,它可能表明继承可能不是最好的解决方案-组合可能是解决这个问题的更好方法。

最好在一个只以类型子类B为参数的方法中调用performTransform,至少您不必进行类型检查


说到这里,如果你有这个问题,这可能意味着遗传可能不是最好的解决方案——构图可能是解决这个问题的更好方法。

仅仅因为你说你的自行车是一辆汽车,并不意味着有地方可以加油。多态性的全部目的是让你把事物想象成一个超级类——这些都是银行账户,这些都是形状,用经典的例子来说——而不是陷入它们真正的样子。有时子类会添加功能。在许多情况下,在每个子类的特定实现中都会使用该功能。因此,为了使用您的名字,超类签名中的某些方法Adjust在子类A和子类B中实现不同。Subassa版本将其自身的性能转换称为过程的一部分,我们从此都过着幸福的生活。当一些代码需要决定是否调用performTransform时,您不再仅仅将其视为一个超类。这不一定是需要解决的问题,只是问题本身。

仅仅因为你说你的自行车是一辆汽车,并不意味着它有地方加油。多态性的全部目的是让你把事物想象成一个超级类——这些都是银行账户,这些都是形状,用经典的例子来说——而不是陷入它们真正的样子。有时子类会添加功能。在许多情况下,在每个子类的特定实现中都会使用该功能。因此,为了使用您的名字,超类签名中的某些方法Adjust在子类A和子类B中实现不同。Subassa版本将其自身的性能转换称为过程的一部分,我们从此都过着幸福的生活。当一些代码需要决定是否调用performTransform时,您不再仅仅将其视为一个超类。这不一定是需要解决的问题,只是问题本身。

为什么不呢?我们不知道这两个类的实现还涉及到什么。据我所知,子类是可以执行转换的超类。使用OOP语言,通常可以向超类中不存在的子类添加行为,使它们更加专业化。在我看来,这仍然是一种关系。但是我知道你是从哪里来的。当然,你可以给子类添加行为,但通常如果你想让子类与超类的接口非常一致,而OP在这里似乎希望这样,你就不会添加公共接口。通常,当我发现自己陷入这样一个陷阱,有一个超类指针,但想对其调用一个可能丢失的方法时,我只是在超类中定义了一个什么都不做或抛出异常版本,该版本在正确的子类中被重写并继续生活。为什么不呢?我们不知道这两个类的实现还涉及到什么。据我所知,子类是可以执行转换的超类。使用OOP语言,通常可以向超类中不存在的子类添加行为,使它们更加专业化。在我看来,这仍然是一种关系。但是我知道你是从哪里来的。当然,你可以给子类添加行为,但是通常如果你想让子类与超类的接口非常一致,而OP在这里似乎希望你这样做

“我们不打算添加公共接口。通常,当我发现自己陷入这样一个陷阱,有一个超类指针,但想调用可能缺少的方法时,我只是在超类中定义了一个do nothing或throw异常版本,该版本在正确的子类中被重写并继续使用。为了改进这种设计,我们需要知道您要解决的问题。我试图将其概括化,因为每当出现这种问题时,我都在寻找一个通用的解决方案。请检查Liskov替换原则您描述的某个问题的解决方案不是特别优雅。为了改进这种设计,我们需要知道您要解决的问题。我一直在尝试将其概括化,因为每当出现这种问题时,我都在寻找一个通用的解决方案。检查Liskov替换原则我一直在寻找使用组合而不是继承的机会,但这并不总是正确的解决方案。我一直在寻找使用组合而不是继承的机会,但这并不总是正确的解决方案。这就是我所认为的情况,但是我想知道,自从15年前我在学校学习这个东西以来,OOP专家们是否已经想出了更好的方法。我的观点是,允许你对任何你想要的对象调用这个方法都不会更好,因为有些人可能不实现它。出于您的目的,您可能需要研究一种动态类型语言,如Python,其中方法调用将导致在运行时检查实例以获取方法的实现。Objective C允许这类操作,但这只是因为默认行为是什么都不做,如果消息处理程序未实现,则不返回任何内容。FWIW,任何时候我看到有人试图解决张贴的问题,丢失类型信息,然后试图取回,这是一个更大的设计问题的迹象。如果您需要类型信息,请保留它。是的,我使用的是动态类型语言,但该行为适用于没有实现方法的运行时异常。@Graham,那么您只需要检查该方法是否存在。在Python中,您可以将其包装在try中:obj.MyMethod;除了属性错误:传递处理程序,但是仔细考虑你的类层次结构,尝试想出一种方法来构造它,这样你就不需要猜测对象支持什么方法。但是我想知道,自从15年前我在学校学习这个东西以来,OOP专家们是否已经想出了更好的方法。我的观点是,允许你对任何你想要的对象调用这个方法都不会更好,因为有些人可能不实现它。出于您的目的,您可能需要研究一种动态类型语言,如Python,其中方法调用将导致在运行时检查实例以获取方法的实现。Objective C允许这类操作,但这只是因为默认行为是什么都不做,如果消息处理程序未实现,则不返回任何内容。FWIW,任何时候我看到有人试图解决张贴的问题,丢失类型信息,然后试图取回,这是一个更大的设计问题的迹象。如果您需要类型信息,请保留它。是的,我使用的是动态类型语言,但该行为适用于没有实现方法的运行时异常。@Graham,那么您只需要检查该方法是否存在。在Python中,您可以将其包装在try中:obj.MyMethod;除了AbjtError:PASS处理程序,但是仔细考虑你的类层次结构,尝试想出一种方法来构造它,这样你就不需要猜测对象支持的方法。