不允许 Circle 实例接受 Point3D 作为中心

Unallow a Circle instance to accept a Point3D as center

我想提交一个 OOP 问题。也许它已经在其他地方解决了,但我找不到它...

想象一下这样的事情(python-类似伪代码)

class Point:
    x: int
    y: int

    # Some methods here    

class Point3D(Point):
    z: int

class Circle:
    center: Point
    radius: int

    # Some methods here

class Sphere(Circle):
    center: Point3D

在静态类型语言中 - 除非我犯错 - Point3D 实例将作为 Circlecenter 属性传递,因为它继承自 Point , 这是不允许的,因为它会变成 Sphere-like.

我们如何在不丢失方法分解的情况下实现这一点?

Liskov Substitution Principle (LSP) 声明用派生 class 的实例替换基 classe 的实例将始终有效。这是 OOP 的核心特性,不是问题。

问题出在你的模型上 -- 让我们考虑一下 2D 点和 3D 点之间的关系是什么。 Point3D 继承自 Point2D 表示 Point3D Point2D,即所有 Point3D也是 Point2D 的。

但这实际上并不适合您的模型!在数学中,只有来自 2D 平面的 3D 点(带有 z == 0 的点)实际上是 2D 点。这种差异是可能将您的 Circle 变成球体的漏洞的来源。

这个 OOP 模型实际上可能是相反的:所有 2D 点 都是 3D 点,z == 0。因此 Point2D 继承自 Point3D 是有道理的。但是,它会带来一系列新的可变性问题:如果您能够将 Point2D 作为 Point3D 访问并修改它,那么您可以将其 z 坐标设置为非零,并以不一致的 Point2D 结束,它实际上不再是 2D。 LSP又坏了


很容易在 OOP 中以任一方向表示 2D 和 3D 点之间的关系:

  • 一个 3D 点包含一个 2D 点不使用的坐标,因此它应该是派生的 class

...或...

  • 在数学上,一个2D点也是一个3D点,所以应该是导出的class

...但最重要的是 class 都不能从另一个 继承,因为 LSP 无论如何都会被破坏。将它们保持为单独的 classes,apples with apples 和 Circles with Point2Ds,如果您需要在点之间分解公共代码,请使用一些其他语言功能——泛型编程,例如例如。