# 本人学习时的笔记,有错必改,不喜勿喷 #
1. 依赖倒置原则(Dependency Inversion Principle,DIP)
- 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定) 。
- 抽象(稳定)不应该依赖于实现细节(变化) ,实现细节应该依赖于抽象(稳定)。
如上例中,高层模块Manager不直接依赖于具体实现类Worker1和Worker2,而是通过抽象接口IWorker来与它们进行交互。这样,当需要新增或替换具体实现类时,不需要修改Manager类,只需要修改Worker1和Worker2类或者增加新的实现类即可。
总结:一切都应优先“面向抽象”编程,也就是说我们在设计之前就应该考虑哪些会变化,哪些又是不会变的。
2. 开放封闭原则(Open/Closed Principle,OCP)
- 对扩展开放,对更改封闭
- 系统设计应该允许新功能的添加或现有功能的修改而不需要修改现有的源代码。这通常通过利用抽象和多态来实现。新的功能应该通过添加新的代码来扩展现有的代码,而不是直接修改已有的代码。
- 类模块应该是可扩展的,但是不可修改
- 一旦设计完成并且实现了,就不应该对其进行修改。这意味着系统的设计应该稳定,并且不需要经常性的修改来适应变化的需求。系统应该通过接口或抽象来隔离变化,使得变化只影响到系统的扩展部分,而不是影响到系统的核心部分。
举例:比如图形绘制程序,我们可以定义抽象基类Shape,其中定义了虚函数virtual void draw()=0,然后由其派生出具体的绘制Circle, Rectangle的类,这样如果我们想添加新的子类triangle则只需直接继承shape然后实现具体的draw函数即可,这样就实现了对扩展开放而对修改封闭的设计原则。
总结:OCP涉及比较多的是封装以及多态,也就是通过基类先定义抽象方法,子类再具体去实现,保证方法的通用性。
3. 单一职责原则(Single Responsibility Principle,SRP)
- 一个类应该仅有一个引起它变化的原因
- 即一个类应该有且仅有一个职责,不应该包含多个不相关的职责。如果一个类承担了多个职责,那么当其中一个职责发生变化时,可能会影响到其他职责,导致类的设计变得复杂和脆弱。
- 变化的方向隐含着类的责任
- 类的设计应该根据它可能发生的变化来划分职责。如果一个类可能有多个变化的方向,那么就意味着它可能包含多个职责,应该考虑将其拆分为多个单一职责的类。
举例:假设有一个名为FileManager的类,它负责管理文件的读取、写入和删除操作。按照SRP原则,这个类实际上包含了多个职责:文件管理和文件IO操作。如果将来需要改变文件管理的方式,可能会影响到文件IO操作,反之亦然。
根据SRP原则,可以将FileManager类拆分为两个单一职责的类:一个负责文件管理(如FileManager),另一个负责文件IO操作(如FileIOManager)。这样,当需要改变文件管理方式时,只需修改FileManager类而不影响FileIOManager类,反之亦然。
总结:在定义一个类之前就应该先考虑好这个类主要干什么事,并且应注意不要让其肩负太多的责任。
- 子类必须能够替换它们的基类(is-a):即在程序中,任何使用基类的地方都应该能够替换为子类,而不会导致程序出现错误或异常行为。这意味着子类应该继承基类的所有行为和属性,并且不能修改基类的行为。
- 继承表达类型抽象:继承关系应该表达出类型之间的抽象关系,而不是具体的实现细节。子类应该符合基类所定义的类型,而且应该尽量减少对基类的修改。
举例:假设有一个图形绘制程序,它有一个Shape基类和派生类Circle和Rectangle。按照LSP原则,任何可以接收Shape对象的地方都应该能够接收Circle或Rectangle对象,而且不应该导致绘制结果错误。
总结:里氏替换原则强调的是is-a的继承关系,与组合模式要区别开。