🚀 0.前言
现状痛点
常常在网上能看到,很多人晒自己碰到的“祖传代码”,“龟派气功式代码”,“shǐ山代码”等等。
可能在此之前你也多少了解过设计模式,但在实际的业务开发中使⽤却不多,多数时候都是⼤⾯积堆积 if else 组装业务流程,
对于⼀次次的需求迭代和逻辑补充,只能东拼⻄凑 Ctrl+C 、 Ctrl+V 。
什么是设计模式
设计模式 Design Pattern 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,
使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。
设计模式是软件设计中常见问题的典型解决方案。 每个模式就像一张蓝图, 你可以通过对其进行定制来解决代码中的特定设计问题。
- 能在白纸上画出所有的模式结构和时序图;
- 能用代码实现;如果模式的代码都没有实现过,是用不出来的;即所谓,看得懂,不会用;
- 灵活应用到工作中的项目中;
-
设计模式来源众多专家的经验和智慧,它们是从许多优秀的软件系统中总结出的成功的、能够实现可维护性复用的设计方案,使用这些方案将可以让我们避免做一些重复性的工作
-
设计模式提供了一套通用的设计词汇和一种通用的形式来方便开发人员之间沟通和交流,使得设计方案更加通俗易懂
-
大部分设计模式都兼顾了系统的可重用性和可扩展性,这使得我们可以更好地重用一些已有的设计方案、功能模块甚至一个完整的软件系统,避免我们经常做一些重复的设计、编写一些重复的代码
-
合理使用设计模式并对设计模式的使用情况进行文档化,将有助于别人更快地理解系统
-
学习设计模式将有助于初学者更加深入地理解面向对象思想
好处
代码复用是减少开发成本,减低复杂度最常用的方式之一,这个想法表面看起来很棒,但实际上要让已有代码在全新的上下文中工作,通常还是需要付出额外努力的。组件间紧密的耦合、对具体类而非接口的依赖和硬编码的行为都会降低代码的灵活性,使得复用这些代码变得更加困难。设计模式目标就是帮助软件提高内聚,减低耦合,使用设计模式是增加软件组件灵活性并使其易于复用的方式之一。
变化是程序员生命中唯一不变的事情,客户需求可能经常会变,紧急上线的版本,要不要下次重构一下,还是继续打各种补丁, 技术债会越积越多,因此在设计程序架构时,所有有经验的开发者会尽量选择支持未来任何可能变更的方式。可扩展性成为了程序设计必须要考虑指标,而设计模式是可以借鉴的,成熟的优化程序设计的解决方案;
总体来说,深刻理解设计模式会给我们带来很多好处:
-
可以和面试官"畅谈"设计模式相关问题.
-
很多开源软件框架大量使用了设计模式,比如Linux系统,Redis,Spring,C++STL等等,可以把帮你加快理解开源软件框架。
-
当你写的代码越来越优美后,你的代码鉴赏能力就会提高,对团队code review贡献也会更大,在个人影响力也会提高。
-
你不会再畏手畏脚,你的工具箱里面工具很多后,可以帮助你,应对各种大型项目的代码设计和开发。
-
每个领域都会一些成熟"套路", 编程也不例外,熟悉这些套路,可以更好方便交流和更快速地解决问题;
为了更好理解设计模式,我们首先要理解一些重要的设计原则,而不是片面理解设计模式哪些模式名词,要看清楚这背后的原理,这个才是最重要的。
📚 1.设计原则
SOLID 原则
- 单一职责原则 SRP
实现类要职责单一:如果一段代码块(函数 类 模块)负责多个功能,那么当 A 功能需求发生改变的时候改动了代码,就有可能导致 B 功能出现问题,所以一段代码块只应该负责一个职责。
- 开放-封闭原则 OCP
要对扩展开放,对修改关闭:通过修改老代码来实现新功能可能导致老模块出现 BUG,所以我们应该通过开发新代码块来实现新功能。
- 里氏替换原则 LSP
不要破坏继承体系:程序中的子类应该可以替换父类出现的任何地方并保持预期不变。所以子类尽量不要改变父类方法的预期行为。
- 接口隔离原则 ISP
设计接口的时候要精简单一:当类 A 只需要接口 B 中的部分方法时,因为实现接口需要实现其所有的方法,于是就造成了类 A 多出了部分不需要的代码。这时应该将 B 接口拆分,将类A需要和不需要的方法隔离开来。
- 依赖倒置原则 DIP
面向接口编程:抽象不应该依赖细节,细节应该依赖于抽象。核心是面向接口编程,我们应该依赖于抽象接口,而不是具体的接口实现类或具体的对象。
6.最少知识原则(迪米特原则)LOD
降低耦合度:一个类或对象应该对其它对象保持最少的了解。只与直接的朋友(耦合)通信。
DRY原则 不要重复你自己
功能语义重复应该合并,代码执行重复应该删减,代码逻辑重复但语义不同应该保留。
KISS原则 尽量保持简单
尽可能使用简单可读性高的代码实现功能,而不用逻辑复杂、实现难度高、可读性差的方式
💻 2.设模式分类
《设计模式:可复用面向对象软件的基础》一书中设计模式有23个,它们各具特色,每个模式都为某一个可重复的设计问题提供了一套解决方案。根据它们的用途,设计模式可分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三种,其中创建型模式主要用于描述如何创建对象,结构型模式主要用于描述如何实现类或对象的组合,行为型模式主要用于描述类或对象怎样交互以及怎样分配职责。
此外,根据某个模式主要是用于处理类之间的关系还是对象之间的关系,设计模式还可以分为类模式和对象模式。我们经常将两种分类方式结合使用,如单例模式是对象创建型模式,模板方法模式是类行为型模式。
1 创建型
创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将模块中对象的创建和对象的使用分离。
为了使结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。
- 简单工厂模式(Simple Factory Pattern)
- 工厂方法模式(Factory Method Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
- 单例模式(Singleton Pattern)
- 生成器模式(Builder Pattern)
- 原型模式(Prototype Pattern)
2 结构型
结构型模式(Structural Pattern)描述如何将类或者对 象结合在一起形成更大的结构,就像搭积木,可以通过 简单积木的组合形成复杂的、功能更为强大的结构。
结构型模式可以分为类结构型模式和对象结构型模式:
-
类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。
-
对象结构型模式关心类与对象的组合,通过关联关系使得在一 个类中定义另一个类的实例对象,然后通过该对象调用其方法。 根据“合成复用原则”,
在系统中尽量使用关联关系来替代继 承关系,因此大部分结构型模式都是对象结构型模式。
- 外观模式
- 适配器模式
- 桥接模式
- 代理模式
- 装饰者模式
- 享元模式
3 行为型
行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。
通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互。
- 职责链模式
- 命令模式
- 解释器模式
- 迭代器模式
- 中介者模式
- 备忘录模式
- 观察者模式
- 状态模式
- 策略模式
- 模板方法模式
- 访问者模式
📁 3.应用实例
单例模式
定义: 保证⼀个类仅有⼀个实例,并提供⼀个 访问它的全局访问点
工厂模式
定义:
策略模式
定义: 定义了一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活、可维护、可扩展。
责任链模式
定义: 职责链模式是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。
模板模式
定义: 定义⼀个操作中的算法的⻣架,⽽将⼀些步骤延迟到⼦类中。模板⽅法使得⼦类可以不改变⼀个算法的结构即可定义该算法的某些特定步骤。
观察者模式
定义: 定义对象间的⼀种⼀对多的依赖关系,当⼀个对象的状态发⽣改变时,所有依赖于它的对象都得到通知并被⾃动更新
📋 4.总结
序号 | 名称 | 业务场景 | 定义和使用 |
---|---|---|---|
5 | 单例模式 | 7种单例模式案例 推荐枚举单例 | 保证⼀个类仅有⼀个实例,并提供⼀个 访问它的全局访问点 |
1 | 工厂模式 | 多种类型商品不同接口,统一发奖服务搭建场景 | |
20 | 策略模式 | 模拟多种营销类型优惠券,折扣金额计算策略场景 | 定义⼀系列的算法,把它们⼀个个封装起来, 并且使它们可相互替换。 |
13 | 责任链模式 | 模拟618电商大促期间,项目上线流程多级负责人审批场景 | 避免请求发送者与接收者耦合在⼀起,让多个对象都有可能接收请求,将这些对象连接成⼀条链,并且沿着这条链传递请求,直到有对象处理它为⽌。 |
21 | 模板模式 | 模拟爬虫各类电商商品,生成营销推广海报场景 | 定义⼀个操作中的算法的⻣架,⽽将⼀些步骤延迟到⼦类中。模板⽅法使得⼦类可以不改变⼀个算法的结构即可᯿定义该算法的某些特定步骤。 |
18 | 观察者模式 | 模拟类似小客车指标摇号过程,监听消息通知用户中签场景 | 定义对象间的⼀种⼀对多的依赖关系,当⼀个对象的状态发⽣改变时,所有依赖于它的对象都得到通知并被⾃动更新 |