我想提交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
个实例将作为center
的{{1}}属性传递,因为它继承自Circle
,必须是不允许的,因为它会变成Point
- 就像。
如何在不丢失方法因素化的情况下实现这一目标?
答案 0 :(得分:1)
Liskov Substitution Principle(LSP)声明用派生类的实例替换base classe的实例应始终有效。这是OOP的核心功能,而不是问题。
问题出在你的模型中 - 让我们考虑2D点和3D点之间的关系。让Point3D
继承Point2D
表示Point3D
是 Point2D
,即所有Point3D
&#39}也是Point2D
。
但这实际上并不符合您的建模!在数学中,只有来自2D平面的3D点(具有z == 0
的3D点)实际上是2D点。这种差异是导致您Circle
成为球体的漏洞的根源。
对此的OOP模型实际上可能相反:所有2D点都是 3D点,z == 0
。因此,从Point2D
继承的Point3D
会有意义。但是,它会带来一系列可变性的新问题:如果您能够Point2D
作为Point3D
访问并修改它,那么您可以将其z
坐标设置为非零,并最终得到一个不一致的Point2D
,它实际上不再是2D。 LSP再次被打破。
在任何方向上表示OOP中2D和3D点之间的关系很诱人:
......或......
...但底线只是两个类都不能继承另一个,因为LSP无论如何都会被破坏。将它们保存为单独的类,带有苹果的苹果和带有Circle
的{{1}} s,如果需要在点之间考虑公共代码,请使用其他一些语言功能 - 例如,通用编程。