2017-04-13 80 views
3

對不起軟件工程上的交叉發佈,不知道它是不是皺起了眉頭。對依賴倒置原理的說明

那裏正是我一直在尋找,對於那些好奇的答案,我得到了:https://softwareengineering.stackexchange.com/a/347143/269571


原來的問題

我讀的書「敏捷軟件開發,原理,模式和實踐「作者:羅伯特C.馬丁

當他對依賴倒置原則說話他給出了DIP違反了下面的例子:

DIP Violation

這在我看來很清楚,因爲Button取決於更高級別的對象一個較低級別的對象Lamp

他自帶的解決方案是:

Solution

他創建了一個接口,這樣的方式Button不再取決於對象Lamp上。

這個理論似乎對我很清楚,但是我不能在實際項目中使用這個原理。

  • 是要確定需要被調用哪些類(實現SwitchableDevice)?

  • 告訴Button他需要打開/關閉哪些設備?

  • 如何你告訴使用的東西抽象的,它需要使用具體事物的對象? (請糾正我,如果這個問題是完全錯誤的)

如果有什麼不清楚我的問題,請讓我知道,我會很高興,以澄清事情你。

+0

@ tobi303 Button'使用抽象類來代替具體的東西,這意味着'Button'不再取決於'Lamp'(或任何具體的東西)。第一個例子,'Button'需要'Lamp',這意味着高級對象取決於低級別對象,級別的對象。取而代之的是反轉:取決於高級對象的低級對象。這正是你想要的DIP。據我讀過這本書,我沒有看到任何**的例子,你會告訴按鈕具體實現它要使用 –

+1

給我一秒鐘我會寫一個答案。在評論中已經太多了blabla;) – user463035818

+0

這是我的問題:誰告訴'Button'它應該使用什麼'SwitchableDevice'的具體實現? –

回答

3

依賴注入的整個點(至少據我所知)是Button不需要知道它正在切換的具體SwitchableDevice

的抽象接口看起來是這樣的:

struct SwitchableDevice { 
    virtual void switchOn() = 0; 
    virtual void switchOff() = 0; 
}; 

而且按鈕可以這樣實現:

struct Button { 
    SwitchableDevice& dev; 
    bool state = false; 
    Button(SwitchableDevice& d) : dev(d) {} 
    void buttonPress(){ 
     if (state) { dev.switchOff(); } 
     else  { dev.switchOn(); } 
     state = !state; 
    } 
}; 

對於按鈕,這就是它!沒有人需要告訴按鈕SwitchableDevice的具體實現是什麼,換句話說:ButtonSwitchableDevice的實現是分離的。

一種可能實現一個Lamp的看起來是這樣的:

struct Lamp : SwitchableDevice { 
    void switchOn(){std::cout << "shine bright" << std::endl;} 
    void switchOff(){std::cout << "i am not afraid of the dark" << std::endl;} 
}; 

而且,可以這樣使用:

int main(){ 
    Lamp lamp; 
    Button button(lamp); 
    button.buttonPress(); 
    button.buttonPress(); 
} 

希望幫助...

的benifit是現在我們可以單獨更改ButtonLamp的實現,而不必在另一部分上更改任何內容。例如,一個ButtonForManyDevices看起來是這樣的:

struct ButtonForManyDevices { 
    std::vector<SwitchableDevice*> devs; 
    bool state = false; 
    Button(std::vector<SwitchableDevice*> d) : devs(d) {} 
    void buttonPress(){ 
     if (state) for (auto d: devs) { d.switchOff(); } 
     else  for (auto d: devs) { d.switchOn(); } 
     state = !state; 
    } 
}; 

而且同樣,你可以無需更改按鈕上的任何徹底改變Lamp的行爲(的SwitchableDevice範圍內,當然同樣ButtonForManyDevices甚至可能。用於切換LampVaccumCleanerMicroWaveOven

+0

恩,是的,這讓事情變得更加清晰。所以你也可以用'SwitchableDevice'對象注入一個數組,迭代該數組並調用該方法? –

+0

@MelvinKoopmans這將是一個不同的按鈕。但是,請注意,您可以將上述'Button'的實現更改爲使用'SwitchableDevices'數組來切換一組設備,並且您不必更改'Lamp'實現的一行或接口'SwitchableDevice ' – user463035818

+2

@MelvinKoopmans爲了跟上這個例子,我認爲更好的方法是按鈕仍然控制**一個**'SwitchableDevice'。然而,可以有一個'CompositeSwitchableDevice'(即一個分離的coord),它仍然實現'SwitchableDevice',但是在它的構造器中有一個'SwitcahbleDevice'的列表。現在按鈕不需要改變,燈也不需要改變。你只是做了依賴注入。 – Default

0

他說,按鈕控制應該比一盞燈更普遍。如果你有一個按鈕可以控制每種類型的按鈕類,那麼你可以結束很多按鈕類。

在第一個例子中,一個描述燈上的按鈕。它基本上是以燈爲起點並將其分解成組件。

在第二個例子中,他正在分割零件並更一般地查看按鈕。

誰將決定哪些類(實現SwitchableDevice)需要被調用?

按鈕和界面之間必須有一個鏈接。

誰告訴Button他需要打開/關閉哪些設備?

Button類將需要實現一種機制來告知它連接到的設備。

你如何告訴一個對象使用抽象的東西它需要使用哪些具體的東西? (如果這個問題完全錯誤,請糾正我)。

因爲從抽象接口派生的對象必須完全實現接口。燈對象必須在某處定義TurnOn和TurnOff方法。

+0

因此,一些其他對象會將「對象」數組插入「Button」的構造函數中。然後'Button'迭代對象並調用方法。 –

+1

我不同意'Button'需要任何機制來確定它所連接的設備。 DI的全部理由是它不需要知道。 – Default

+0

按鈕可以有一個指向實現SwitchableInterface的對象的成員。一個按鈕可能會控制一個對象。 – user3344003