设计模式都是为了让代码迎合其中一个或多个设计原则而出现的,所以面向对象的设计原则可以说是设计模式的基础思想。
设计模式的七大设计原则核心思想:
- Single Responsibility Principle:单一职责原则
- Open Closed Principle:开放封闭闭原则
- Liskov Substitution Principle:里氏替换原则
- Law of Demeter:迪米特法则(最少知识原则)
- Interface Segregation Principle:接口隔离原则
- Dependence Inversion Principle:依赖倒置原则
- Composite Reuse Principle:合成复用原则
也有一些人用 SOLID 表示设计原则,首字母组合,最后一个合成复用原则被认为不够经典也不容易违背。
单一职责原则
一个类(大到模块,小到函数)只做一件事情,至于对象的粒度就得自己界定。
如果一个方法需要因为外部原因去改写,那么可以认为这个方法就有两个原则。
如果一个方法承担了过多的职责,那么在需求的变迁过程中,需要改写这个方法的可能性就越大。
当两个职责耦合在一起的时候,一个职责发生变化可能会影响到其他职责的实现,造成意想不到的破坏,这种耦合性得到的是低内聚和脆弱的设计。
单一职责完全体现了高内聚低耦合,提高代码的复用性、可读性、可维护性。。
在实际开发过程中,也应该避免过度设计,可以先写一个比较粗粒度的模块,当模块越来越庞大的时候进行拆分,进行所谓的持续重构。
无法判断是否单一的时候就从代码量和依赖量和私有方法数量来衡量。
就像 webpack 的 loader,可以把 style-loader 和 css-loader 整合成一个,然而没有,我们需要自己都去安装,可以组合之后使用,也可以单独使用,符合了单一职责原则。
开放封闭闭原则
软件实体(类、模块、函数)等应该是可以扩展的,但是不可修改。也就是说,对扩展是开放的,而对修改是封闭的。
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
大部分设计模式都是为了解决代码的扩展性,扩展性是代码质量的重要指标。
也必须注意,对修改封闭并不意味着一直堆代码,而是尽可能的找出可变和不可变的部分,更少的修改代码,而不是完全不修改。
开发中运用开放封闭原则最重要的是对业务或者功能要有很清晰的认知,知道未来可能要添加的功能或者如何被使用。
里氏替换原则
任何基类/父类可以出现的地方,子类一定可以出现。并且保证原来程序的逻辑行为不变及正确性不被破坏。里氏代换原则是对“开-闭”原则的补充。
有一点需要特别注意,子类可以替换父类,父类的修改却会影响所有子类。
当子类重写父类逻辑的时候,最终的实现不能违反父类,否则就是违反里氏替换原则。
迪米特法则(最少知识原则)
一个软件实体应当尽可能少的与其他实体发生相互作用。每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
迪米特法则的初衷在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。
接口隔离原则
客户端不应该依赖它不需要的接口。使用多个专门的接口比使用单一的总接口要好。一个类对另一个类的依赖应该建立在最小的接口上。
接口不一定完全理解成 API 接口,也就是请求接口,也可以理解成函数或者类等的调用。
接口隔离原则跟单一职责原则有点类似,都是让接口尽量单一,把接口拆分的更细,单一职责原则针对的是模块、类、接口的设计。接口隔离原则更侧重于接口的设计。
依赖倒置原则
程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变动时上层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。
面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。
理解起来有点抽象,JavaScript 中我理解的就是高阶函数,通过回调和传参让依赖解耦。typescript 的出现算是更好的在 JavaScript 实现依赖倒置原则?
合成复用原则
尽量使用对象组合,而不是继承来达到复用的目的。JavaScript 中应该更推荐合成复用原则。比如函数 A 使用函数 B 的一些功能,可以继承、传参、变量去使用,如果使用合成复用原则,那就是用传参或者变量调用函数 B 的功能,如果是继承,那么函数 A 就和函数 B 耦合了。
理解了几个设计原则,一定要非常注意过度设计,不要为了设计原则而进行超出实际意义的设计。比如开放封闭原则,别为了未来不一定需要,或者要很久才需要的功能进行非常复杂的设计,也需要权衡一定的可读性可维护性,别设计了一些功能,结果只有自己能看懂。
设计原则有时候会有一些主观方面的判断和理解,大多时候也很难符合那么多原则,有时候还会出现符合一个原则违反另外一个原则,都得做衡量和取舍。自己觉得好像是有一点理解了,实际运用又是另外一回事,而且有些原则很抽象,对前端开发并不那么友好,自己到现在也是对一些原则没有很好的概念。
欢迎关注订阅号 coding个人笔记