# design-pattern
**Repository Path**: uRick/design-pattern
## Basic Information
- **Project Name**: design-pattern
- **Description**: 深入设计模式实践,探究Java设计模式的代码复用,提升编码思维与质量。
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-10-13
- **Last Updated**: 2022-10-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 1. 设计模式
**本仓库仅作为学习探索资源**
## 1.1. 代码模板
- code template
```template
/**
* ${PROJECT_NAME}
* ${PACKAGE_NAME}
* @author uRick rickwork@163.com
* @version 1.0.0
* date: ${DATE} ${TIME}
*/
```
- readme template
---
```text
project: ${PROJECT_NAME}
package: ${PACKAGE_NAME}
author: uRick rickwork@163.com
version: 1.0.0
date: ${DATE} ${TIME}
```
---
## 1.2. 设计原则
在了解设计模式之前,先要理解设计模式的6大设计原则,很有必要,所有的设计模式都是围绕这6大原则设计,复用代码,提高代码的可维护性、可读性以及软件质量。
1. **单一职责原则—Simple Responsibility Pinciple, SRP**
面向对象中,在类、接口功能属性设计上尽可能保证职责单一,具体如何设计还是要根据业务需求来完成,也就避免类、接口设计过于臃肿,不利于组件复用、可移植性、灵活性;该原则实践中仁者见仁智者见智,每个设计者都有自己的理解和依据。
2. **里式替换原则—Liskov Substitution Principle, LSP**
在面向对象开发的继承体系中,子类可以扩展父类的功能,但不能改变父类原有的功能,但在实践中,很多设计并未完全遵守该原则,实现要求:
- 子类可以实现父类的抽象方法,但是不能覆盖/重写父类的非抽象方法;`实践中,为了拓展流程,覆盖流程时会违背该原则`
- 子类中可以增加自己特有的方法;`新增新方法`
- 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松;`父HashMap,子Map,其实这里不应该是重写了,而是重载;体现出,在使用过程中,首先使用父类方法`
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格或相同。`返回值类型更具体,如父List,子ArrayList`
3. **依赖倒置原则—Dependence Inversion Principle, DIP**
各个功能模块之间应该依赖抽象,而不是依赖细节;“面向抽象编程,细节应该依赖抽象”。
该原则减少了类之间的耦合性,保证类设计的稳定,提供代码组织的可维护性以及可读性;同时避免了需求变动修改带来的风险,在面向对象开发中,要面向抽象编程(接口、抽象类),细节依赖抽象拓展功能。
4. **接口隔离原则—Interface Segregation Principle, ISP**
该原则的思想就是让设计的接口职责单一,也就是尽可能的小,避免设计过于臃肿的接口,不利于后期拓展业务;实践中要根据业务触发来设计,脱离业务都是耍流氓。
5. **迪米特原则—Law of Demeter, LoD**
迪米特原则又叫最少知道原则,尽量降低类之间的耦合程度,不相关的类,不应当纠缠不清;“只跟朋友交流,不与陌生人说话”。
6. **开闭原则—Open-Closed Principle, OCP**
一个类、模块和函数应该对“扩展开放,对修改关闭,抽象构建架构,实现拓展细节”,在面向对象的开发中,遵守开闭原则,要以“抽象”为核心来拓展开发,确定抽象底层,极少变动(修改关闭),拓展由具体实现类来完成。对于抽象层的定义,需要设计者具备优秀的抽象思维能力,能够预见未来的所有拓展功能,因为它作为拓展的根基,定以后不应该随便更改,尽可能保证稳定性;对于拓展,只需复用抽象以及现有实现的组件来拓展衍生出新的功能组件。
7. **合成复用原则(拓展)—Composite/Aggregate Reuse Principle, CARP**
指尽量使用对象组合(has-a)/聚合(contanis-a),而不是继承关系达到软件复用的目的。可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
继承我们叫做白箱复用,相当于把所有的实现细节暴露给子类。组合/聚合也称之为黑箱复用,对类以外的对象是无法获取到实现细节的。
## 1.3. 设计模式分类
统一建模语言,类图符号关系:
```text
依赖:带箭头的虚线表示依赖关系
泛化:使用带空心箭头的实线表示,箭头指向父类(继承)
关联:用一条实线来表示关联关系
聚合:用一个带空心菱形的实线表示,空心菱形指向的是代表“整体”的类
实现:用一个带空心箭头的虚线表示(实现接口)
属性&方法可见性
“+”表示public方法和字段,可以从类外部访问这些方法和字段。
“-”表示private方法和字段,无法从类外部访问这些方法和字段。
“#”表示protect方法和字段,能够访问这些方法和字段的只能是该类自身、该类的子类以及同一包中的类。
“~”表示只有同一包中的类才能访问的方法和字段。
```
1. 创建型
> 创建型是通过对象实例化过程的抽象,定义抽象的接口,封装对象创建的时机。
| 序号 | 类型 | 英文 | 说明 |
| :--: | :----------: | :---------------: | :-------------------------------------------------------------------------------------------------------------------- |
| 1 | 抽象工厂模式 | Abstract Factory | 提供创建一组或一系列或相互依赖对象的接口, 适合基于工厂创建不同的产品系列 |
| 2 | 构造器模式 | Builder | 创建复杂对象时,可以使用构造器模式,将复杂的构建过程或状态屏蔽在构造器中 |
| 3 | 工厂方法模式 | Factory Method | 具体的创建对象,由子类或者拓展类来实现;适用于某个类创建实例不清楚具体由那个子类创建的, 通过工厂方法来传相关参数实现 |
| 4 | 原型模式 | Prototype | 以现有的对象,通过原型拷贝获取一个新的对象 |
| 5 | 单例模式 | Singleton | 只允许创建一份实例对象 |
2. 结构型
> 结构型主要用于组合已有的类或对象生成一个更大的体系结构,一般采用继承组合接口来实现,对外提供统一的功能。
| 序号 | 类型 | 英文 | 说明 |
| :--: | :--------: | :-------: | :--------------------------------------------------------------------------------------------------- |
| 1 | 适配器模式 | Adapter | 将一类接口转换为另一类接口,通常用于接口适配兼容性问题,包括对象适配(组合)、类适配(继承) |
| 2 | 桥接模式 | Bridge | 将接口与实现分离,分离两个独立相关的组件,组件之间通过组合关联,关联对象可以是抽象或实现 |
| 3 | 组合模式 | Composite | 组合复杂的对象,”部分与整体“的关系,适合具有相同特征的组件抽象 |
| 4 | 装饰模式 | Decorator | 动态的为对象添加额外的责任或功能 |
| 5 | 外观模式 | Facade | 对外提供统一的接口,屏蔽内部接口或子系统的细节 |
| 6 | 享元模式 | Flyweight | 通过共享对象来降低性能开销,也就是“通过共享实例,而避免new实例” |
| 7 | 代理模式 | Proxy | 代理某个对象处理相关事务,实践中常见用在”面向切面“拓展编程中,如记录日志、构建监控、植入插件程序等 |
3. 行为型
> 行为型主要用于对象之间的职责以及提供服务的分配,不仅是描述对象和类的模式,还描述他们之间的通信模式。
| 序号 | 类型 | 英文 | 说明 |
| :--: | :----------: | :-------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | 责任链模式 | Chain | 对象之间,业务流程之间可以通过责任链传递消息,每一个链之间具有相关链性,前一个链输出作为下一个链的输入 |
| 2 | 命令模式 | Commond | 把接收的请求封装为对象,做为参数传递,并把请求放入队列中,按操作执行相关命令,支持撤销操作 |
| 3 | 迭代器模式 | Iterator | 提供数据集合的遍历方式,简化集合遍历,提供统一遍历接口 |
| 4 | 解释器模式 | Interpreter | 通常用于解释定义的语言或表达式,通过上下文传输层层解析(类似迭代)语法结构,实际工作中使用较少 |
| 5 | 中介者模式 | Mediator | 用Mediator对象来封装一系列的对象交互,降低对象间的耦合度,不直接引用对象,而是通过中间人协调;
可以把该模式理解为一种思想,当不想对外暴露过多的功能组件时,可以通过中间者来协调、仲裁、通讯 ,对外仅暴露中间者 |
| 6 | 备忘录模式 | Memento | 备忘录模式也可以叫后悔药模式,通过备忘录来记录历史版本记录(保存快照),可以支持撤销、重做;
实践中常见的版本管理、游戏存档、程序发布与该模式有很多相似之处 |
| 7 | 观察者模式 | Observer | 观察主体事件,实时广播观察到的消息 |
| 8 | 状态模式 | State | 其本质就是把变化的状态封装到对象中,状态的变化通过对象来传递,实践中可以用于复杂的状态切换场景。
在项目开发中很多状态维护都是面向过程的开发方式,随着状态增大,出现大量`if-else`,
导致可读性、可维护性极差,而通过`state`模式改造后,业务代码易于理解、结构清晰、拓展性更高,
对状态进行分类,不同类别做不同的状态切换操作 |
| 9 | 策略模式 | Strategy | 算法与业务分离,把算法封装为独立的策略组件,业务根据需求动态使用不同策略算法替换 |
| 10 | 模板方法模式 | Template Method | 抽象类根据处理流程提供模板方法,子类实现该模板方法,适用于对通用流程的封装 |
| 11 | 访问者模式 | Visitor | 将数据处理与数据结构分离,可以理解为“解耦业务处理与数据”,适合对数据处理操作变更频繁的场景 |

## 1.4. 参考资源
1. 《图解设计模式》——结城洁著,杨文轩译
2. [Refactoring](https://refactoringguru.cn/refactoring)
3. [Gof23设计模式速记(迷你图)](https://blog.csdn.net/lilongsy/article/details/102475296)
4. 《重学Java设计模式》——小傅哥著