浅析设计模式 - 概述

本文目录:

概述

设计模式与语言无关,用来解决一些反复出现的问题的解决方案

基本原则

面向对象设计的基本原则,有两点是我们想要达到的

  • 可维护性
  • 可复用性

如果放到实际开发中可以这样简单理解:

可维护性好的代码,就是需求改动对现有的代码改动小、副作用低而且可控,而不是牵一发而动全身

可复用性好的代码,就是如果有需求实现方案类似,有代码可以复用,直接省去重复造轮子的时间。最理想的是热插拔,即插即用。再差点就是稍微改动就可以复用。最差的就是代码和其他模块的一些没必要的关联和依赖太多,因为依赖于实现和不是抽象,所以又得把实现加进来等等,剪不断理还乱,复用的成本比再造个轮子高。

因为我们的产品在不断快速地迭代,需求也在不断地变化。如果维护性降低和复用性降低,我们的迭代速度会越来越慢,缺少设计和保养的代码会因为某些微不足道的改动而产生一系列 bug,开发周期变长,每次改动新增 bug 数变多,能做的需求变少,会被一些快速迭代的竞品蚕食掉市场

所以,一定要注意代码的结构和设计。别人也要维护这块代码,前人栽树,后人乘凉

六大基本原则,SOLID + 迪米特法则

单一职责原则

Single Responsibility Principle,SRP

定义:一个类只负责一个功能领域中的相应职责

别让一个类承担太多职责。这会产生两个问题,一是职责复用,其他地方也需要复用这个职责,因为没有从该类解耦出去,对该类持有不必要的引用;二是可能会导致某些类间的职责相互耦合和依赖,一个职责发生变化,其他职责也会受影响

比如我们有一个类,做了很多种任务,既有数据访问、业务逻辑、UI展示都有,然后各部分相互耦合相互依赖。迭代过一阵子,代码会迅速膨胀,而且其他场景如果要进行功能复用的话会很难受。所以这里可以做拆分,拆成几个类,各司其职

单一职责

该原则主要的目的就是解耦和增强内聚性,而且降低类的复杂度,逻辑也变得简单,更好理解和维护

也要控制好粒度。实际应用中,也不要把粒度做得非常小,这会导致类的数量过多。

开闭原则

Open Closed Principle, OCP

定义:软件实体应对扩展开放,而对修改关闭

软件实体指:

  • 按一定逻辑规则划分的模块
  • 抽象和类
  • 方法

这个意味着,新需求过来后,我们尽量不修改旧代码中的方法和类,而是创建新方法、新类

实现该原则,需要用抽象构建整体框架,细节用实现扩展细节。意味着,抽象层要做得好,足够稳定,然后需求来了后,我们只需要去修改或者扩展子类实现,用极小的改动完成需求

开闭原则

里氏替换原则

Liskov Substitution Principle,LSP

定义:所有引用基类对象的地方能够透明地使用其子类的对象

如果我们定义了一个基类,如果把它的引用换成了子类的对象,不会对程序造成破坏。

所以,我们的基类可以是对业务的抽象,至于业务使用什么样的实现,可以动态去创建,而不同的实现对于使用者来说是透明的,使用者只需要看到抽象基类。子类的不同实现,都可以让程序正常运行

同样,我们的程序在扩展的时候,只要增加新的子类而不会动到原有的子类,这样可以把代码改动的风险降低。这样的话就实现了开闭原则

比如我们平时使用 List,针对 List 接口的方法编程的地方,后面把引用引向它的几个子类,都不会对代码原有逻辑造成破坏

接口隔离原则

Interface Segregation Principle,ISP

定义:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

其实就是要对一个有大量方法的接口进行拆分和细化

拆分的方式,可以对接口中的方法进行归类,找到哪些方法是一起使用的,让接口中的方法数尽量少

因为我们实现了某接口,就要实现它的所有方法,但如果这个接口大杂烩而我们只需要部分方法,却要去实现大量空方法,还要去理解它,这个封装就不达标了。合格的封装,应该让使用者只看到和实现需要的方法

比如下面的例子。像左边的情况,一个接口内堆积了大量的方法,但是 A 只需要三个,导致一些 A 不需要的方法也暴露出来了。B 也是一样。可以拆分成右边的情况。实际情况会更复杂

接口隔离

接口拆分粒度也不能太小,粒度太小接口类多起来也不好维护

如果接口内方法大量堆积,臃肿,而且实现方每次只使用部分方法,可以考虑拆分一下了

依赖倒置原则

Dependence Inversion Principle,DIP

定义:抽象不应该依赖于细节,细节应该依赖于抽象

Java 中,抽象就是接口或者抽象类;细节就是实现类

原因是实现细节变化很多,如果让抽象依赖于实现细节,会导致某些细节的变化引起抽象类的变化,进而又引起该抽象类的实现类的变化,代码维护困难,改动量大容易犯错

比如,我们需要一个列表,直接使用 ArrayList,后来需求发现变动,发现这个 ArrayList 被多线程访问了,想用 CopyOnWriteArrayList 替换,但基本上所有的参数声明、变量声明都用了 ArrayList,整个改动很大

但如果我们一开始就是基于 ArrayList 的抽象 List 编程,只需要调整一下,选择 CopyOnWriteArrayList 实现就好了

依赖倒置

遵循一些规则:

  • 类尽量有抽象类或者接口
  • 变量声明的类型尽量是接口或者抽象类

面向接口编程,在开发可以很方便地更换实现

依赖倒置原则虽好,但是使用起来还是要根据具体的业务场景,如果强行去创建各种抽象类和接口,过度使用,会造成很多类的浪费。而且依赖于抽象也要看场景,有时候就必须依赖于细节

迪米特法则

一个软件实体应当尽可能少地与其他实体发生相互作用

让类与类之间的关联和耦合,这样一个模块发生修改时,尽量地少影响其他模块

法则定义包括:不要和陌生人说话,只与直接朋友通信

一个对象的朋友有:

  • 当前对象本身
  • 以参数形式传入到当前对象方法中对象
  • 当前对象的成员对象
  • 如果当前对象的成员是一个集合,集合中的元素也都是朋友
  • 当前对象所创建的对象

每一个类都应当降低成员变量和成员函数的访问权限

而一个对象对其他对象的访问,可以使用第三者来代理或者转发

也可以采用抽象的方式,去依赖其他对象的抽象而不是具体实现。比如 MVP 的设计模式,各层之间采用接口的形式进行通信,而具体的实现不可见。这样子后面改实现或者替换实现,各层次不会有大的干扰

主要内容

是什么?什么是设计模式

定义:设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。

组成成分:名称、问题、目的、解决方案、效果

长期实践的成果,是这几十年软件编程中总结的经验。踩坑踩出来的,应用模式来提高软件的可维护性和可复用性。各行各业都有自己的模板和套路,可以认为设计模式就是软件设计的一些套路

设计模式是对既有方案的优化,每个模式都有自己的优缺点,我们要做的就是取长补短,让它的优点发光发热

为什么?为什么要应用设计模式

能很好地应对需求变化,用尽可能少的改动新增需求,扩展性好,可以提高开发的效率。稳定的结构,可维护性好,高内聚,低耦合,避免代码膨胀而发生牵一发而动全身的情况。

能很好地进行代码复用,避免重复造轮子,避免了不必要的体力活

阅读上的改善,写代码容易读代码难,但有有应用设计模式的话,并且理解其中的设计思路,可以帮助我们理解代码。设计模式在一些开源库和源码中应用很多,所以也是一把打开开源世界代码的钥匙

怎么做?如何应用设计模式

抽象公共,封装变化。基于抽象和接口编程,多用组合,少用继承。可以是模板方法模式,让子类用继承实现变化的方法。可以是策略模式,使用者使用算法的抽象,具体场景在动态选择算法实现。也可以是桥接模式,让抽象和实现单独变化,用组合代替继承来增加多维度的功能

依赖转移,把依赖关系转移到类外。比如采用设值注入,或者构造注入。这个看具体的场景使用。采用设置注入或者构造注入,把依赖关系转移到外面,可以降低类之间的耦合。如果有单元测试,这个做法会为单元测试带来便利

功能分离,让每个类或者每个方法执行单一的职责和功能。但是这个地方是要合理控制粒度的,拆得太细了,会导致类和方法泛滥膨胀。有些场景代码量小,修改量小,如果很执着地在很小的粒度上应用设计模式,反而会导致结构复杂,理解困难,修改繁琐。所以最重要的是合适,而不是生搬硬套。

迭代细化,可以一开始定一个初步的模型,用简单的用例描述整体的设计。然后在去细化每一个点。如果开发中发现有设计不合理的地方,及时调整模型的结构,不断增强和完善。可以使用 UML 图进行辅助设计

思考未来变化。如果以后需求变化了,我们是不是要改动很多地方。如果应用了某个模式,是否可以减少这块代码的改动。方便以后用尽可能少的代码完成需求(改动越大,越容易出错)。但是思考未来变化不能过度思考,过度思考会把原本很简单的模型做得很复杂。

适当调整改造。设计模式不是一成不变的,我们借助这些理论和思想,多思考,然后从整体理论出发,做出一些设计上的调整。经常会使用多个设计模式进行组合,设计和实现功能。也有的会对模式做一些调整。比如责任链模式,严格的话每个节点可以选择消费掉任务不转发,但我们也可以调整为消费掉事件并且转发等等。

尽可能地朝基本原则靠拢,去符合开闭原则

主要分类

24 种

创建型

关注对象的创建

做依赖反转,创建和实现的解耦,封装复杂的创建过程

6 种

  • 单例模式
  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式
  • 原型模式
  • 建造者模式

结构型

和创建型不一样,这个地方关注的是整体设计的静态结构,就像在建房子一样,这里关注的是怎么设计房屋的钢结构

关注类的组合关系

7 种

  • 适配器模式
  • 桥接模式
  • 组合模式
  • 装饰模式
  • 外观模式
  • 享元模式
  • 代理模式

行为型

关注类的的动态行为,即对象与对象之间的交互

11 种

  • 职责链模式
  • 命令模式
  • 解释器模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 状态模式
  • 策略模式
  • 模板方法模式
  • 访问者模式

猜你喜欢

转载自blog.csdn.net/firefile/article/details/80570858