> For the complete documentation index, see [llms.txt](https://yangsx95.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yangsx95.gitbook.io/notes/computer-science/she-ji-mo-shi.md).

# 设计模式

## 设计模式六大原则

SOLID:

1. Single Responsibitity Principle 单一职责原则
2. Open Close Principle 开放封闭原则
3. Liskov Substitution Principle 里氏替换原则
4. Interface Segregation Principle 接口分离原则
5. Dependence Inversion Principle 依赖倒置原则
6. Least Knowledge Principle 迪米特法则

### 开闭原则（核心原则）

开闭原则规定软件中的对象、类、模块和函数对扩展应该时开放的，但是对于修改时封闭的。这意味着应该用抽象定义结构，用具体实现扩展细节，以此确保软件系统开发和维护过程的可靠性。开闭原则就是三个顶层的代码设计思维：

1. 抽象意识
2. 封装意识
3. 扩展意识

> 关键字：实现只添加代码，不修改代码的设计，最典型的就是策略模式以及工厂模式

优点：

1. 新老逻辑解耦，需求发生变化时不会影响老业务
2. 改动成本最小，只需要增加逻辑
3. 提供代码的稳定性与可扩展性

示例：

1. 系统A与系统B之间数据传输时，约定协议时，要考虑协议的可以变性，抽取具有报文编译、编制、校验等所有版本协议使用的通用方法，面向接口开发。当出现新的协议时，可以在不更改代码的情况下增加新的协议实现。

### 单一职责原则

一个类或者模块只负责完成一个职责。一个类只负责完成一个职责或者功能，在也就是说，在设计类时，不要设计大而全的类，而是要设计力度小、功能单一的类。

> 关键词： 职责单一

例如：

1. 实体对象/表 的设计中有与主体关联性弱的信息，这类需要根据实际的业务场景信息进行拆分，如果某些字段的信息有可能发生扩展，且扩展内容与主体有可能关联性弱，这类字段就应该单独提取出来。比如，UserInfo中的地址信息，如果地址信息后期有可能发生扩展、修改，那么该信息就应该单独提取出表。
2. 接口的设计，接口是否只能有一个功能

如何判断一个类的职责是否单一：

1. 类的代码行数、函数、属性过多
2. 类以来的类过多
3. 类的四方方法过多
4. 类中的大量方法总是操作类中的几个属性

### 接口隔离原则

一个类对另一个类的依赖应该建立在最小的接口上。每一个接口应该承担独立的角色，不敢不该自己干的事，避免子类实现不需要的接口方法，需要对客户提供接口的时候，只需要暴露最小的接口。

> 关键字：接口职责单一

优势：

1. 将庞大臃肿的接口分为多个细粒度的接口，可以提高系统的灵活性和可维护性
2. 使用多个专门的接口，还能够体现出对象的层次
3. 能够减少项目工程中的冗余代码

示例：

1. 比如接口 `Flyable`和 `Runnable`两个接口，不可以合二为一
2. 在JUC中，Executor 与 ExecutorService，Executor只提供一个execute方法，剩余的有子接口 ExecutorService进行功能扩展，就很好的遵守了接口隔离原则。**备注：** 如果是符合接口隔离原则的组合的Interface，在理解Interface时，将接口名单词拆分更好理解，以ExecutorService为例，可以拆分为Executor + Service，前者代表继承Executor接口，拥有执行的能力，后者则代表提供一系列服务的方法。
3. Runnable、Future 以及他们的组合接口 RunnableFuture

### 里氏替换原则

简单来说，就是一个方法的参数假设是一个接口，那么这个方法可以处理所有这个接口的实现类，方法中不应该有特殊操作。并且是接口的哪儿种派生类的实现，都与接口或者积累方法的期望行为一致。

以下代码既符合开闭原则，也符合里氏替换原则：

```java
// 类型转换，将任意类型转换为String
public static class Converter {
    String convert(String value);
}
// converter是可替换的，且无论什么方法都是返回一个string
public static String convert(Converter converter, Object target) {
    return converter.convert(target);
}
```

### 依赖倒置原则

依赖接口，不要依赖接口具体的实现。

### 迪米特法则（最少知道原则）

指一个类/模块对其他的类/模块有越少的了解越少。典型的迪米特法则的设计模式有适配器模式。通过中间人，降低类之间、模块之间的耦合性。

> 不该有直接依赖关系的类之间，不要有依赖；有依赖关系的类之间，尽量只依赖必要的接口。

## 设计模式分类

### 创建型模式

* `Singleton`，[单例模式](/notes/computer-science/she-ji-mo-shi/dan-li-mo-shi.md)：保证一个类只有一个实例，并提供一个访问它的全局访问点。
* `Builder`，[建造模式](/notes/computer-science/she-ji-mo-shi/jian-zao-zhe-mo-shi.md)：将一个复杂对象的构建与他的表示相分离，使得同样的构建过程可以创建不同的表示。
* `Prototype`，[原型模式](/notes/computer-science/she-ji-mo-shi/yuan-xing-mo-shi.md)：用原型实例指定创建对象的种类，并且通过拷贝这些原型来创建新的对象。
* `Factory`，[工厂模式](/notes/computer-science/she-ji-mo-shi/gong-chang-mo-shi.md)
  * `Simple Factory`，简单工厂，使用一个简单的标记获取这个标记对应的类实例。
  * `Factory Method`，工厂方法：定义一个用于创建对象的接口，让子类决定实例化哪一个类，Factory Method使一个类的实例化延迟到了子类。
  * `Abstract Factory`，抽象工厂：提供一个创建一系列相关或相互依赖对象的接口，而无须指定它们的具体类。

### 结构型模式

共享池：

* `Flyweight`，[享元模式](/notes/computer-science/she-ji-mo-shi/xiang-yuan-mo-shi.md)，共享单元放入享元池，以节省存储空间，是池技术的表现

扩展对象的功能：

* `Proxy`，[代理模式](/notes/computer-science/she-ji-mo-shi/dai-li-mo-shi.md)：为其他对象提供一种代理以控制对这个对象的访问
* `Decrator`，[装饰模式](/notes/computer-science/she-ji-mo-shi/zhuang-shi-zhe-mo-shi.md)：动态地给一个对象增加一些额外的职责，就增加的功能来说，Decorator模式相比生成子类更加灵活。

处理复杂对象关系：

* `Bridge`，[桥接模式](/notes/computer-science/she-ji-mo-shi/qiao-jie-mo-shi.md)：将抽象部分与它的实现部分相分离（多维度分离），使他们可以独立的变化。
* `Adapter`,[适配器模式](/notes/computer-science/she-ji-mo-shi/shi-pei-qi-mo-shi.md)：将一类的接口转换成客户希望的另外一个接口，Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以一起工作。
* `Facade`，[外观模式](/notes/computer-science/she-ji-mo-shi/wai-guan-mo-shi.md)：为子系统中的一组接口提供一致的界面，facade提供了一高层接口，这个接口使得子系统更容易使用。
* `Composite`，[组合模式](/notes/computer-science/she-ji-mo-shi/zu-he-mo-shi.md)：将对象组合成**树形结构**以表示部分整体的关系，Composite使得用户对单个对象和组合对象的使用具有一致性。

### 行为型模式

* `Event Driven`，[事件驱动](/notes/computer-science/she-ji-mo-shi/shi-jian-qu-dong.md)
  * `Observer`，观察者模式：定义对象间一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知自动更新。
  * `PubSub`，发布订阅模式
* `FSM`，[README](/notes/computer-science/she-ji-mo-shi/you-xian-zhuang-tai-ji.md)
  * 状态迁移表示法。
  * `State`，状态模式：允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。

行为抽象暴露：

* `Strategy`，[策略模式](/notes/computer-science/she-ji-mo-shi/ce-le-mo-shi.md)：定义一系列的算法，把他们一个个封装起来，并使他们可以互相替换，本模式使得算法可以独立于使用它们的客户。
* `Command`，[命令模式](/notes/computer-science/she-ji-mo-shi/ming-ling-mo-shi.md)：将一个请求封装为一个对象，从而使你可以用不同的请求对客户进行参数化，对请求排队和记录请求日志，以及支持可撤销的操作。
* `Interpreter`，[解释器模式](/notes/computer-science/she-ji-mo-shi/jie-shi-qi-mo-shi.md)：给定一个语言，定义他的文法的一个表示，并定义一个解释器，这个解释器使用该表示来解释语言中的句子。

模板行为抽象暴露：

* `Template Method`，[模板方法模式](/notes/computer-science/she-ji-mo-shi/mu-ban-fang-fa-mo-shi.md)：定义一个操作中的算法的骨架，而将一些步骤延迟到子类中，TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。
* `Iterator`，[迭代器模式](/notes/computer-science/she-ji-mo-shi/die-dai-qi-mo-shi.md)：提供一个方法顺序访问一个聚合对象的各个元素，而又不需要暴露该对象的内部表示。
* `Memento`，[备忘录模式](/notes/computer-science/she-ji-mo-shi/bei-wang-lu-mo-shi.md)：在不破坏对象的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。
* `Chain of Responsibility`，职责链模式：使多个对象都有机会处理请求，从而避免请求的送发者和接收者之间的耦合关系
* `Mediator`，中介者模式：用一个中介对象封装一些列的对象交互。
* `Visitor`，访问者模式：表示一个作用于某对象结构中的各元素的操作，它使你可以在不改变各元素类的前提下定义作用于这个元素的新操作。
