2017-09-14 45 views
0

我想提交一個面向對象的問題。也許它已在其他地方解決,但我沒能找到它......取消允許一個圓形實例接受三維點爲中心

想象這樣的事情(蟒蛇般的僞代碼)

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 

在staticly類型langage - 除非我請輸入一個錯誤 - Point3D實例將作爲center屬性傳遞給Circle,因爲它從Point繼承,因爲它將變成類似Sphere的狀態,因此它必須被禁用。

我們怎樣才能做到這一點不失方法因式分解?

回答

1

Liskov Substitution Principle(LSP)指出,用派生類的實例替換基類的實例應始終有效。這是OOP的核心功能,而不是問題。

的問題是在你的模型 - 讓我們考慮一個2D點和3D點之間的關係是什麼。從Point2DPoint3D繼承規定一個Point3DPoint2D,即所有Point3D的也Point2D的。

但這實際上並不適合你造型的!在數學中,只有來自2D平面的3D點(具有z == 0的點)實際上是2D點。這種差異是漏洞,可能會變成你的Circle成球形的來​​源。

OOP模型實際上可能是相反的:所有2D點都是 3D點,其中z == 0。因此Point2DPoint3D繼承那種纔有意義。它將,但是,開闢一個新的問題與可變性:如果你能夠訪問一個Point2DPoint3D並修改它,那麼你可以設置其z座標爲非零,並與不一致Point2D結束這實際上不再是2D。 LSP再次被破壞。


人們很容易表示在任一方向的2D和3D點在OOP之間的關係:

  • 一個3D點包含一個多個座標,一個2D點不使用,從而它應該是派生類

...或...

  • 數學上,2D p oints也是一個三維點,所以應該是派生類

...但底線很簡單,既不類可以從其他的一個繼承,因爲LSP被打破無論哪種方式。將它們保持爲單獨的類,蘋果與蘋果,並使用Point2D s,並使用其他語言功能,如果您需要在點之間考慮通用代碼 - 例如通用編程。

+0

非常清楚,謝謝你的解釋!但是我正在考慮使用抽象超類來[[幹]](https://en.m.wikipedia.org/wiki/Don%27t_repeat_yourself)...(現在甚至可以在Python中用ABC也叫抽象基類)抽象類不能是實例化的,'Point2D'和'Point3D'不能互相繼承,所以LSP是受到尊重的。你的意見? –

+0

是的,只要你注意在基類中只包含兩類實際共有的東西,那將是有效的。 – Quentin

相關問題