2016-11-13 32 views
2

我想了解并应用SOLID原则。 关于依存倒置原则,这是否意味着禁止对象的合成/聚合? 因此,必须始终使用一个接口来访问另一个类方法?固体:DIP是否意味着禁止物体的合成/聚合?

我的意思是:

class ServiceClass { 
    void serviceClasshelper(); 
} 

class MainClass { 
    void MainClass(ServiceClass service); // To use serviceClasshelper 
} 

必须改成:

class ServiceInterface { 
    virtual void interfaceHelper() =0; 
} 

class ServiceClass : public ServiceInterface { 
    void serviceClasshelper(); 
    void interfaceHelper() { serviceClasshelper(); }; 
} 

class MainClass { 
    void MainClass(ServiceInterface service); // Uses interfaceHelper 
} 

我认为(或至少我希望如此),我明白一个道理。 但是不知道它是否可以像这样改写。 的确,我读到的关于DIP的东西建议使用接口。

谢谢!

回答

2

基本上,DIP的主要思想是:

  • 高级别模块应该不依赖于低电平的模块。 应该取决于抽象。
  • 抽象应该不依赖细节。细节应该取决于抽象。

正如你所看到的,它说:应该,而不是必须。它并不禁止你做任何事情。

如果您的课程composite of/aggregate to其他具体classes(而不是interfaces/abstract classes),它是好的!你的代码仍然可以编译和运行,不会显示任何警告,告诉你:“嘿,你违反了DIP”。所以我认为你的问题的答案是:不,它不是

想象一下,您的系统由一千个班级组成,您可以将DIP应用到2个班级,并且其中一个班级取决于第三个特定班级(而不是interfaces/abstract classes)。只要你的问题解决了,什么都不重要。所以尽量保持你的解决方案简单 - >易于理解。相信我,当你回顾你的解决方案时,你会发现它有价值。

DIP是一个指导原则,它告诉你当你面对一组特定的问题以解决它们时要做什么。这不是一个神奇的指导方针,它的代价是:复杂度。你应用DIP越多,你的系统就会越复杂。所以明智地使用它。为了进一步支持这一点,我建议你看看这个参考文献(摘自Head First: Design Patterns书)。访问此link(它是一个PDF文件),并在顶部栏导航到页面635/681。或者,如果你够懒,只是阅读以下报价:

你的头脑模式

初学者使用的图案无处不在。这很好:初学者获得大量的经验并练习使用模式。初学者 也认为,“我使用的图案越多,设计越好。” 初学者将会知道这并非如此,所有的设计应尽可能简单为 。复杂性和模式只能在实际可扩展性需要的地方使用 。

随着学习的进展,中级思维开始看到哪里需要模式,哪些模式不需要。中间心理 仍尝试将太多的方形图案装入圆孔中,但 开始发现可以调整图案以适应典型图案不适合的情况。

禅意能够看到自然适合的图案。禅意并不着迷于使用模式;而是寻找最适合解决问题的简单解决方案 。禅意在 认为对象原则的条款和他们的权衡。当自然需要一个 模式时,禅意就会很好地运用它,因为它知道它可能需要适应。禅意也看到了与 类似模式的关系,并且理解了相关模式意图差异的细微之处。禅意也是一个初学者的头脑 - 它不会让所有这种模式知识过度影响设计 的决定。

最后,我将指向你四个设计模式的刚认为,利用DIP的:Strategy

例题:一个Character可以使用3种武器:HandSword,& Gun 。他(Character)可以随时换掉目前的武器。

分析:这是一个非常典型的问题。棘手的部分是如何在运行时处理武器交换。

候选解与策略:(只是一个SketchUp的):

enter image description here

weapon = new Hand(); 
weapon.Attack(); // Implementation of Hand class 

weapon = new Sword(); 
weapon.Attack(); // Implementation of Sword class 

weapon = new Gun(); 
weapon.Attack(); // Implementation of Gun class 

其他设计模式&框架,利用DIP的:

+0

非常感谢您的回答!我觉得你完全是我的担忧。关于体验与设计模式使用的部分可能会为我节省很多时间。您可能会让我在使用设计模式的不同方式之间漫游很多时间。非常感谢您的回答:)。 – Plouff

+0

我认为系统越复杂,你就会应用DIP越多。 –

+0

@AdrianIftode:如果应用DIP使系统不那么复杂,我会称之为“糟糕设计”系统而不是“复杂”系统。这里提供了一个参考资料,它提到了安装设计模式时系统的复杂程度:https://youtu.be/gwIS9cZlrhk?t = 4153 –

1

是的,这是正确的,DIP说你需要依赖抽象(接口)而不是结核(实际实现的类)。

这个想法是,如果你依赖于ServiceClass,你依赖于这个特定的实现,你不能轻易地用另一个实现来替换它。例如,您有AnotherServiceClass,但要使用它而不是ServiceClass,则必须从ServiceClass继承它,这可能不合乎要求,甚至不可能。虽然具有接口依赖性,但您可以轻松完成此操作。

更新:这里是上面

// Service class does something useful (sendNetworkRequest) 
// and is able to report the results 
class ServiceClass { 
    void reportResults(); 
    void sendNetworkRequest(); 
} 

// Main logger collects results 
class MainLogger { 
    void registerService(ServiceClass service); 
} 

说明的想法更具体的例子,我们有我们传递给MainLogger::registerServiceServiceClass,记录器(例如)定期调用service->reportResults()并保存到文件中。现在

,假设我们有另一个服务:

// Service class does something useful (calculateYearlyReport) 
// and is able to report the results 
class AnotherServiceClass { 
    void reportResults(); 
    void calculateYearlyReport(); 
} 

如果我们只是用具体的类在这里和来自ServiceClass继承AnotherServiceClass,我们就能把它传递给MainLogger::registerServcie,但除了违反DIP ,我们也将违反LSP(因为子类不能用作BaseClass的替代品)和ISP(因为我们在这里显然有不同的界面 - 一个用于报告结果,另一个用于执行有用的工作),并且还会违反一个更好的规则更喜欢composition over inheritance

直接传递ServiceClass实例的另一个缺点就是现在不能保证MainLogger不依赖于内部结构(访问其他方法/成员等)。

还有一点是代码维护的简易性 - 当您看到该接口已通过时,您只需查看两个对象之间通信的“协议”即可。在使用具体类时,您实际上需要通过实现来了解如何使用传递的对象。

因此,一般情况下最好遵循SOLID和其他OOP原则,尽可能使代码更清晰,更容易支持,并让您避免以后难以修复的错误。

+0

非常感谢您的回答了。你澄清了DIP的含义,现在我可以说我明白了。希望我能够很快学会何时“明智地”使用它。 – Plouff