这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战
从今天开始我们来学习设计原则,如单一职责原则(SRP)、开闭原则、里氏替换原则、接口隔离原则和依赖替换原则等
单一职责原则(SRP)
什么是单一职责原则?
一个类或一个模块只负责完成一个职责(功能) 。也就不说我们不要设计大而全的类,而是设计颗粒度小、功能单一的类,如果说一个类包含了两种及以上的业务不相干的功能,那么就说他的职责不够单一,应该进行拆分。
如何判断类的职责是否足够单一?
不同阶段的不同场景,对同一个类的职责是否单一,可能会有不同的判定结果。一些判断指标更具有指导意义和可执行性,比如:
- 类中代码行数、函数、属性过多,私有方法过多
- 很难给类取一个合适的名字
- 类中大量的方法只是在集中操作几个属性
- 类依赖其他的类过多,或者依赖类的其他类过多
是不是越单一越好?
不是。单一职责原则是通过避免设计大而全的类,避免将不相干的功能耦合在一起,来提高类的内聚性。如果拆分得过细,会适得其反,反倒会降低内聚性,影响代码的可维护性。
开闭原则
什么是开闭原则?
开闭原则就是对扩展开放,对修改关闭。在添加一个新功能时,应该是在已有代码基础上扩展代码(新增模块、方法等),而不是去修改原有的代码。我们需要注意的是,一是开闭原则并不是完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发;二是同样的代码改动可能是“修改”也可能是“扩展”。为什么要开闭原则呢?对扩展开放是应对新的功能需求,对修改关闭是保持原有代码的稳定性,目的是让系统更有弹性。
如何做到开闭原则?
我们要时刻具备扩展意识、抽象和封装意识。在写代码的时候要多思考一下,这个地方为了可能会有什么需求变更,我们要如何设计好代码结构,留好扩展点,然后在将来新需求的时候以最小代码改动的情况下来完成,很多设计模式都是以提高代码扩展性为目的的。
里式替换(LSP)
什么是里式替换?
里式替换是指子类对象能够替换程序中的父类对象出现的任何地方,并保持原有程序的逻辑行为不变以及正确性不被破坏。
里式替换原则是用来指导继承关系中子类如何设计的一个原则。核心是按“按协议来设计“,父类定义了函数的“约定(协议)”,子类可以改变函数内部实现的逻辑,但不能改变函数原有的“约定”,如函数声明要实现的功能、对输入输出的约定等。
里式替换原则和多态有点类似,但他们关注的角度不一样。多态是面向对象编程的一大特性,也是面向对象编程语言的一个语法,是一种代码实现的思路;而里式替换是一个设计原则,指导继承关系中子类如何设计,在替换父类的时候不改变原有程序的逻辑和不破坏原有程序的正确性。
接口隔离原则
如何理解“接口隔离原则“?
接口隔离原则重点是“接口”二字。客户端不应该强迫依赖他不需要的接口,客户端可以看做接口的调用者,或使用者
- “接口”理解为一组接口集合,可能是某个类库的接口,如果部分接口只给部分调用者使用,那我们需要将他们隔离出来,单独给他们用,不强迫其他调用者依赖这部分不会用到的接口。
- “接口”理解为单个API或者函数,调用者只需要调用其中的部分功能,那么我们可以把他们拆成颗粒度更细的多个函数,让调用者只需依赖他需要的那个系颗粒度函数。
- “接口”理解为OOP中的接口,那么接口设计尽量单一,不要让接口的实现类和调用者依赖不需要的接口函数。
依赖替换原则
“依赖反转”这个概念指的是“谁跟谁”额“什么依赖”被反转了?“反转”两个字怎么理解?除此之外,我们还经常听到“控制反转”和“依赖注入”,他们有什么区别和联系呢?
控制反转
控制反转是比较笼统的设计思想,不是一种具体的方法实现,一般用来指导框架层面的设计。“控制”是指对程序执行流程的控制,“反转”是指在没有使用框架之前,程序员自己控制整个程序的执行。使用框架之后,程序的执行流程由框架控制,流程的控制权由程序员“反转”给了框架。
依赖注入
依赖注入和控制反转刚好相反,他是一种具体的编码技巧。我们不在类的内部去new一个他依赖的类对象,而是在外面将他的依赖的类对象初始化好后通过构造函数或函数参数传入(注入)
依赖注入框架
通过依赖注入框架提供的扩展点,简单配置一下所有需要的类以及类与类之间的依赖关系,就实现了框架来自动创建对象,管理对象的生命周期,依赖注入等程序员要做的事。
依赖反转原则
依赖反转原则也叫做依赖倒置原则。这原则跟控制反转有点相似,主要指导框架层面的设计。高层模块不依赖底层模块,他们共同依赖一个抽象,抽象不需要一个具体的实现细节,具体实现细节依赖抽象
参考:《设计模式之美 — 王争》