2017-08-29 107 views
2

我在程序中有一個設計問題,這是由於abstract基地有一個方法帶有一個位置(因此是可選的)參數。如何在方法有可選參數時不違反Liskov替換原則?

比方說這個班級是A,方法是void f(x, [y]);。現在,y是可選的,因爲我已經知道一些A的子類將使用它,其中一些不會。

實際的問題是違反了里氏替換原則:在需要y子類我不得不拋出一個異常,如果不提供y,而在A.f(這是未實現的),我不拋出任何異常。

A的設計也不好,因爲我提供了一個方法f,其中一些子類真的需要它,其中一些需要稍微不同的版本。顯然,我應該儘可能小地設計我的接口(接口隔離)。

這實際上是一個普遍的問題,不僅與飛鏢有關。

那麼,如何處理可選參數以避免違反Liskov替換原則?特別是,您將如何處理我的情況,以便我也不違反界面隔離原則?

唯一可行的解​​決方案(我的具體問題),我現在看到的是使延長A和實際f需要y實際延長(或實現,如果A實際上是一個接口),另一個基類電流子方法f(x, y),這是兩個參數都是必需的。但是如何處理可選參數的問題仍然存在!

+0

參數x和y有什麼共同點嗎?也許你可以把它們「包裝」成一種新的類型。這樣你就只有'f'的一個參數。 –

+0

@JanezKuhar我也想過這個選項,但是創建另一個類型只是爲了明顯地解決這個參數問題,它看起來像一個黑客,因爲問題實際上依然存在,也就是'A的子類'f' '最初需要'y'(現在已經打包了另一個類型),如果'y'沒有被傳遞,仍然會拋出異常,而不需要'y'的其他子類不會。 – nbro

+0

這是真的 - 只是掩蓋了問題。 –

回答

0

我真的沒有看到LSP和可選參數之間的連接。根據你的代碼,你會違反原則,你對這些參數做了什麼不是因爲語言提供給你的選項。

在你的例子中,我會說至少可以說你會違反LSP,因爲A是抽象的(因此你不能實例化它),你不能直接調用f,因爲它沒有實現。

讓我們省略該部分,並說你有A類和B類(具體),並且都實現方法f(x, [y])

然後假定你有a作爲Ab的實例作爲B的實例。給定[x,y]的任何值,如果您使用a.f(x,y)的任何地方,則可以使用((A)b).f(x,y),並且得到完全相同的結果,則表明您沒有違反LSP。

無論如何,如果你覺得你可能違反了LSP,那麼你必須問自己,你是否真的需要層次結構。而不是聲明BA子類的,也許你可以有一個接口由AB與普通方法來實現,使你們在使用B到另一個類A有代碼,您可以從AB(見https://en.wikipedia.org/wiki/Composition_over_inheritance)調用。

+0

_你會違反原則,這取決於你的代碼,以及你對params所做的不是因爲語言提供給你的選項._是的,我在說我的問題是我需要拋出一個異常,如果'y '不提供給需要'y'的擴展'A'的類的方法'f'。 – nbro

+0

所以,爲了更清楚,這裏的問題是你可以調用'a'的'f'作爲'af(x)',它永遠不會拋出異常,而某些'bf(x)',對於某些情況'B'的某個子類的'b',將會。先決條件得到加強! – nbro

+0

順便說一句,你的最後一個建議與我所建議的唯一解決方案類似,在我的問題中我可以看到那一刻。 – nbro

2

當我閱讀它時,問題是你想要的子類實際上不能替代超類。您需要兩個類AB來實現相同的API,即使這些類不是真正可互換的。 其中一個只使用一個參數(可以說,應該只有接受一個參數),另一個參數需要兩個參數。這兩個類是不兼容的,因此添加一個通用的超類,以某種方式抽象出不兼容的操作,註定會失敗。

也就是說,如果你已經知道A的某些子類不會使用foo的第二個參數,那他們爲什麼是A的子類呢?因爲作爲A的子類,他們應接受A接受的任何論點,並以與A.foo文檔中的合同一致的方式使用它。

問題不是可選參數,它是超類中的可選參數。如果一個參數在超類中是可選的,那麼它在所有的子類中也是可選的,因爲子類需要以超類的方式被調用。 (x, [y])的函數不能被一個只需要一個或兩個參數的函數替代,反之亦然。 子類必須允許更多比超類更多,並且從可選參數變爲不可選允許減去

如果你有類

class X { foo(x) {} } 
class Y { foo(x, y) {} } 
class Z implements X, Y { foo(x, [y]) {} } 

然後它因爲Z允許比任何XY更多。使用Z作爲超類而不是子類將不起作用,這與聲音和安全性相反。

0

的里氏替換原則的基本格言是:使用指針或引用基類必須能夠使用派生類的對象而不自知

功能。

換句話說: - 類應基於行爲而不是性能建模; - 數據應基於屬性而不是行爲建模。

所以在你的情況下,我會說這是違規行爲,因爲可選參數不會成爲其他子類行爲的一部分。最好將它作爲使用它的子類的一部分。

以下是令人驚歎的SOLID principles的漂亮圖片!

enter image description here

相關問題