二、设计原则SOLID

二、设计原则

2.1、五大设计原则(SOLID)


1、SRP 单一职责原则

一个类只负责完成一个职责或者功能。不要设计大而全的类,要设计粒度小、功能单一的类。单一职责原则是为了实现代码高内聚、低耦合,提高代码的复用性、可读性、可维护性。

  • 如何判定某个类的职责是否够“单一”

1、类中的代码行数、函数或属性过多,会影响代码的可读性和可维护性,我们就需要考虑对类进行拆分;
2、类依赖的其他类过多,或者依赖类的其他类过多,不符合高内聚、低耦合的设计思想,我们就需要考虑对类进行拆分;
3、私有方法过多,我们就要考虑能否将私有方法独立到新的类中,设置为 public 方法,供更多的类使用,从而提高代码的复用性;
4、 比较难给类起一个合适名字,很难用一个业务名词概括,或者只能用一些笼统的Manager、Context 之类的词语来命名,这就说明类的职责定义得可能不够清晰;
5、类中大量的方法都是集中操作类中的某几个属性,那就可以考虑将这几个属性和对应的方法拆分出来。

2、OCP 开闭原则

添加一个新的功能,应该是通过在已有代码基础上扩展代码(新增模块、类、方法、属性等),而非修改已有代码(修改模块、类、方法、属性等)的方式来完成。
开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发。
同样的代码改动,在粗代码粒度下,可能被认定为“修改”;在细代码粒度下,可能又被认定为“扩展”

3、LSP 里式替换原则

核心的就是理解“design by contract,按照协议来设计”


父类定义了函数的“约定”(或者叫协议),那子类可以改变函数的内部实现逻辑,但不能改变函数原有 的“约定”。这里的约定包括:函数声明要实现的功能;对输入、输出、异常的约定;甚至包括注释中所罗列的任何特殊说明。

4、ISP 接口隔离原则

1、如果把“接口”理解为一组接口集合,如果部分接口只被部分调用者使用,我们就需要将这部分接口隔离出来,单独给这部分调用者使用,而不强迫其他调用者也依赖这部分不会被用到的接口。


2、如果把“接口”理解为单个 API 接口或函数,部分调用者只需要函数中的部分功能,那我们就需要把函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个细粒度函数。


3、如果把“接口”理解为 OOP 中的接口,那接口的设计要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数。

5、DIP 依赖倒置原则

  1. 控制反转

控制反转是一个比较笼统的设计思想,并不是一种具体的实现方法,一般用来指导框架层面的设计。这里所说的“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员“反转”给了框架。

  1. 依赖注入

依赖注入和控制反转恰恰相反,它是一种具体的编码技巧。我们不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类来使用。

  1. 依赖注入框架

通过依赖注入框架提供的扩展点,简单配置一下所有需要的类及其类与类之间依赖关系,就可以实现由框架来自动创建对象、管理对象的生命周期、依赖注入等原本需要程序员来做的事情。

  1. 依赖反转原则

高层模块不依赖低层模块,它们共同依赖同一个抽象。
抽象不要依赖具体实现细节,具体实现细节依赖抽象。

2.2、 DRY 原则、KISS 原则、YAGNI 原则、LOD 法则


KISS 原则

不要使用同事可能不懂的技术来实现代码;
不要重复造轮子,要善于使用已经有的工具类库;
不要过度优化

YAGNI 原则(You Ain’t Gonna Need It。你不会需要它)

不要做过度设计
不要去设计当前用不到的功能;不要去编写当前用不到的代码

DRY 原则(Don’t Repeat Yourself。不要重复自己)

1、DRY 原则

三种代码重复的情况:实现逻辑重复、功能语义重复、代码执行重复。实现逻辑重复,但功能语义不重复的代码,并不违反 DRY 原则。实现逻辑不重复,但功能语义重复的代码,也算是违反 DRY 原则。除此之外,代码执行重复也算是违反 DRY 原则。

2、 代码复用性

1、减少代码耦合

对于高度耦合的代码,当我们希望复用其中的一个功能,想把这个功能的代码抽取出来成为一个独立的模块、类或者函数的时候,往往会发现牵一发而动全身。移动一点代码,就要牵连到很多其他相关的代码。所以,高度耦合的代码会影响到代码的复用性,我们要尽量减少代码耦合。

2、满足单一职责原则

如果职责不够单一,模块、类设计得大而全,那依赖它的代码或者它依赖的代码就会比较多,进而增加了代码的耦合,影响到代码的复用性。相反,越细粒度的代码,代码的通用性会越好,越容易被复用。

3、模块化

将功能独立的代码,封装成模块。独立的模块就像一块一块的积木,更加容易复用,可以直接拿来搭建更加复杂的系统。

4、业务与非业务逻辑分离

越是跟业务无关的代码越是容易复用,越是针对特定业务的代码越难复用。所以,为了复用跟业务无关的代码,我们将业务和非业务逻辑代码分离,抽取成一些通用的框架、类库、组件等。

5、通用代码下沉

从分层的角度来看,越底层的代码越通用、会被越多的模块调用,越应该设计得足够可复用。一般情况下,在代码分层之后,为了避免交叉调用导致调用关系混乱,我们只允许上层代码调用下层代码及同层代码之间的调用,杜绝下层代码调用上层代码。所以,通用的代码我们尽量下沉到更下层。

6、继承、多态、抽象、封装

继承,可以将公共的代码抽取到父类,子类复用父类的属性和方法。
多态,可以动态地替换一段代码的部分逻辑,让这段代码可复用。
抽象,越抽象、越不依赖具体的实现,越容易复用。
封装,封装成模块,隐藏可变的细节、暴露不变的接口,就越容易复用。

7、应用模板等设计模式

LOD 法则(Law of Demeter; 迪米特法则; 最小知识原则)

“高内聚、松耦合”是一个非常重要的设计思想,能够有效提高代码的可读性和可维护性,缩小功能改动导致的代码改动范围。“高内聚”用来指导类本身的设计,“松耦合”用来指导类与类之间依赖关系的设计。

  • 高内聚

    相近的功能应该放到同一个类中,不相近的功能不要放到同一个类中。相近的功能往往会被同时修改,放到同一个类中,修改会比较集中,代码容易维护。
    单一职责原则是实现代码高内聚非常有效的设计原则

  • 松耦合

    在代码中,类与类之间的依赖关系简单清晰。即使两个类有依赖关系,一个类的代码改动不会或者很少导致依赖类的代码改动。
    依赖注入、接口隔离、基于接口而非实现编程,以及迪米特法则,都是为了实现代码松耦合

  • LOD 法则

    不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。迪米特法则是希望减少类之间的耦合,让类越独立越好。每个类都应该少了解系统的其他部分。一旦发生变化,需要了解这一变化的类就会比较少。

猜你喜欢

转载自blog.csdn.net/weixin_46488959/article/details/126918351