一、设计原则
SOLID原则:
并非单纯的一个原则,而是由5个设计原则组成,它们分别是单一职责原则、开闭原则、里式替换原则、接口隔离原则和依赖反转原则,依次对应SOLID中的S、O、L、I、D这五个英文字母。
1、单一职责原则(SRP)
1.1 如何理解单一职责原则
单一职责原则的英文是Single Responsibility Principle,缩写为SRP。这个原则的英文描述是这样的:A class or module should have a single reponsibility。如果把它翻译成中文,那就是:一个类或者模块只负责完成一个职责(或者功能)。
不要设计大而全的类,要设计粒度小、功能单一的类。单一职责原则是为了实现代码高内聚、低耦合,提高代码的复用性、可读性、可维护性。
1.2 如何判断类的职责是否足够单一
不同的应用场景、不同阶段的需求背景、不同的业务层面,对同一个类的职责是否单一,可能会有不同的判定结果。实际上,一些侧面的判断指标更具有指导意义和可执行性,比如,出现下面这些情况就有可能说明这类的设计不满足单一职责原则:
- 类中的代码行数、函数或属性过多,会影响代码的可读性和可维护性,我们就需要考虑对类进行拆分
- 类依赖的其他类过多,或者依赖类的其他类过多,不符合高内聚、低耦合的设计思想,我们就需要考虑对类进行拆分
- 私有方法过多,我们就要考虑能否将私有方法独立到新的类中,设置为public方法,供更多的类使用,从而提高代码的复用性
- 比较难给类起一个合适名字,很难用一个业务名词概括,或者只能用一些笼统的Manager、Context之类的词语来命名,这就说明类的职责定义的可能不够清晰
- 类中大量的方法都是集中操作类中的某几个属性,比如,在一个类中,如果一半的方法都是在操作类中的某几个属性,那就可以考虑将这几个属性和对应的方法拆分出来。
1.3 类的职责是否设计的越单一越好
单一职责原则通过避免设计大而全的类,避免将不相关的功能耦合在一起,来提高类的内聚性。同时,类职责单一,类依赖的和被依赖的其他类也会变少,减少了代码的耦合性,以此来实现代码的高内聚、低耦合。但是,如果拆分得过细,实际上会适得其反,反倒会降低内聚性,也会影响代码的可维护性。
实际上,不管是应用设计原则还是设计模式,最终的目的还是提高代码的可读性、可扩展性、复用性、可维护性等。我们在考虑应用某一个设计原则是否合理的时候,也可以以此作为最终的考量标准。
2、开闭原则
1.1 如何理解开闭原则
开闭原则的英文全称是Open Closed Principle,简写为OCP。它的英文描述是:software entities (modules, classes, functions, etc.) should be open for extension , but closed for modification。我们把它翻译成中文就是:软件实体(模块、类、方法等)应该“对扩展开放、对修改关闭”。
添加一个新的功能,应该是通过在已有代码基础上扩展代码(新增模块、类、方法、属性等),而非修改已有代码(修改模块、类、方法、属性等)的方式来完成。关于定义,我们有两点要注意。第一点是,开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发。第二点是,同样的代码改动,在粗代码粒度下,可能被认定为“修改”;在细代码粒度下,可能又被认定为“扩展”。
如何做到对扩展开放、对修改关闭?
我们要时刻具备扩展意识、抽象意识、封装意识。在写代码的时候,我们要多花点时间思考一下,这段代码未来可能有哪些需求变更,如何设计代码结构,事先留好扩展点,以便在未来需求变更的时候,在不改动代码整体结构、做到最小代码改动的情况下,将新的代码灵活地插入到扩展点上。
很多设计原则、设计思想、设计模式,都是以提高代码的扩展性为最终目的的。特别是23种经典设计模式,大部分都是为了解决代码的扩展性问题而总结出来的,都是以开闭原则为指导原则的。最常用来提高代码扩展性的方法有:多态、依赖注入、基于接口而非实现编程,以及大部分的设计模式(比如,装饰、策略、模板、职责链、状态)
二、设计模式的六大原则 总原则是开闭原则: 对扩展开放,对修改关闭 程序需要扩展了,那么不能修改原有的代码,而是对原有代码进行扩展。 为了让程序更加具有扩展性,尽量使用接口和抽象类来进行系统的设计。 1、单一职责原则 一个类应该实现单一职责即可。 如果这个类需要完成多个功能,则将其类分解。 2、里式替换原则 里式替换原则是面向对象设计的基本原则之一。任何基类可以出现的地方,子类一定可以出现。里式替换原则是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。 3、依赖倒转原则 面向接口编程,依赖于抽象而不是具体的实现。 4、接口隔离原则 每个接口不存在子类用不到却必须实现的方法。 如果有上面的问题,则需要将接口进行拆分。 5、迪米特原则(最少知道原则) 类与类之间关系尽量小,耦合度降低。 6、合成复用原则 尽量使用合成和聚合(弱关联)设计系统,不要过多使用继承。