昨天我問了this的問題,而@JB Nizet發佈的解決方案完美運作。然而,這個答案以及其他一些答案/評論讓我思考了一個完全不同的方向。面向對象:如何編寫類的家庭一起工作?
從本質上講,我有以下類別:
Load
HttpLoad extends Load
Target
HttpTarget extends Target
Controller
的Controller
的工作是Target::fire()
一個Load
,並且不關心哪個Target
被解僱這Load
:
// Inside Controller.java
Target target = getTarget();
Load load = getLoad();
target.fire(load);
不過,我可能有一天寫一FtpLoad extends Load
,我不希望能夠火一個FtpLoad
在HttpTarget
。所以上面提到的問題的本質是我該如何做到這一點,其中,答案是泛型。
但是,正如回答者指出的那樣,該解決方案違反了Liksov替代原則。其他回答者/評論者似乎表明我所做的並不一定是好的面向對象的做法。
所以我現在要問:我怎麼暴露的API,以便Controller
可以Load
- 和Target
-agnostic,但仍執行了正確的Load
子類是在正確的Target
型發射,全部在不違反Liskov換人?
而且,如果這是不可能的(不違反Liskov),那麼對於這樣的問題的正常方法是什麼?提前致謝!
我稱之爲模板繼承。使用繼承是因爲事物具有很多通用的功能/屬性,但實際上並沒有任何多態關係。 「正常」的方法是無論如何都要做,並且擁有充滿「支持」方法或類似的笨重API。另一種方法是封裝和多次調度,但是人們發現很難理解。 – Affe
經驗法則:重寫的方法幾乎總是違反了Liskov可替代性,因爲它們在用於替代超類型時會改變子類型的行爲。 –
更改行爲不違反原則。縮小前置條件或擴大後置條件。當將繼承用於框架模板化任務而不是建模多態關係時,通常會發生這種情況。 – Affe