关于依赖倒置原则的澄清

时间:2017-04-13 17:36:57

标签: c++ dependency-injection interface dependency-inversion

请原谅我在软件工程上的交叉发布,不知道它是不受欢迎的。

我得到的答案正是我所寻找的,对于那些好奇的人:https://softwareengineering.stackexchange.com/a/347143/269571

原始问题

我正在阅读 Robert C. Martin "敏捷软件开发,原则,模式和实践" 这本书。

当他谈到依赖性倒置原则时,他给出了以下DIP违规示例:

DIP Violation

这对我来说非常清楚,因为较高级别的对象Button依赖于较低级别的对象Lamp

他带来的解决方案是:

Solution

他创建了一个界面,以便Button不再依赖于对象Lamp

这个理论对我来说似乎很清楚,但是我无法在真实的项目中使用这个原理。

  • 将确定需要调用哪些类(实现SwitchableDevice)?

  • 告诉Button他需要打开/关闭哪些设备?

  • 如何告诉对象使用 abstract 哪些具体需要使用的东西? (如果这个问题完全错误,请纠正我)

如果对我的问题不清楚,请告诉我,我很乐意为你澄清事情。

2 个答案:

答案 0 :(得分: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();
}

希望有帮助...

好处是,现在我们可以单独更改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

答案 1 :(得分:0)

他说按钮控制的东西应该比一盏灯更普遍。如果你有一个按钮可以控制的每种类型的按钮类,那么你最终可以使用很多按钮类。

在第一个例子中,一个是描述灯上的按钮。它主要是以灯为起点并将其分成组件。

在第二个例子中,他正在分割部件并更普遍地查看按钮。

  

谁将确定需要调用哪些类(实现SwitchableDevice)?

按钮和界面之间必须有一个链接。

  

谁告诉Button他需要打开/关闭哪些设备?

Button类需要实现一种机制来告诉它连接到哪个设备。

  

你如何告诉一个使用抽象的对象需要使用哪些具体的东西? (如果这个问题完全错误,请纠正我。)

因为从抽象接口派生的对象必须完全实现该接口。 Lamp对象必须在某处定义TurnOn和TurnOff方法..