auto commit

This commit is contained in:
CyC2018 2018-03-17 20:50:09 +08:00
parent 7d3e36bd35
commit 9c7c1f1e04

View File

@ -1,75 +1,77 @@
<!-- GFM-TOC -->
* [前言](#前言)
* [设计模式入门](#设计模式入门)
* [观察者模式](#观察者模式)
* [装饰模式](#装饰模式)
* [工厂模式](#工厂模式)
* [单件模式](#单件模式)
* [命令模式](#命令模式)
* [适配器模式](#适配器模式)
* [外观模式](#外观模式)
* [模板方法模式](#模板方法模式)
* [迭代器模式](#迭代器模式)
* [组合模式](#组合模式)
* [状态模式](#状态模式)
* [代理模式](#代理模式)
* [复合模式](#复合模式)
* [与设计模式相处](#与设计模式相处)
* [剩下的模式](#剩下的模式)
* [一、前言](#一前言)
* [二、设计模式概念](#二设计模式概念)
* [三、策略模式](#三策略模式)
* [三、观察者模式](#三观察者模式)
* [四、装饰模式](#四装饰模式)
* [五、简单工厂](#五简单工厂)
* [六、工厂方法模式](#六工厂方法模式)
* [七、抽象工厂模式](#七抽象工厂模式)
* [八、单例模式](#八单例模式)
* [九、命令模式](#九命令模式)
* [十、适配器模式](#十适配器模式)
* [十、外观模式](#十外观模式)
* [十一、模板方法模式](#十一模板方法模式)
* [十二、迭代器模式](#十二迭代器模式)
* [十三、组合模式](#十三组合模式)
* [十四、状态模式](#十四状态模式)
* [十五、代理模式](#十五代理模式)
* [十六、MVC](#十六mvc)
* [十七、与设计模式相处](#十七与设计模式相处)
<!-- GFM-TOC -->
# 前言
# 一、前言
文中涉及一些 UML 类图,为了更好地理解,可以先阅读 [UML 类图](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E6%80%9D%E6%83%B3.md#1-%E7%B1%BB%E5%9B%BE)。
文中涉及一些 UML 类图,为了更好地理解,可以先阅读 [UML 类图](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E6%80%9D%E6%83%B3.md#%E7%AC%AC%E4%B8%89%E7%AB%A0-uml)。
需要说明的一点是,文中的 UML 类图和规范的 UML 类图不大相同,其中组合关系使用以下箭头表示:
<div align="center"> <img src="../pics//09e398d8-9c6e-48f6-b48b-8b4f9de61d1d.png"/> </div><br>
# 设计模式入门
**1. 设计模式概念**
# 二、设计模式概念
设计模式不是代码,而是解决问题的方案,学习现有的设计模式可以做到经验复用。
拥有设计模式词汇,在沟通时就能用更少的词汇来讨论,并且不需要了解底层细节。
**2. 问题描述**
# 三、策略模式
## 模式定义
定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
## 问题描述
设计不同种类的鸭子拥有不同的叫声和飞行方式。
**3. 简单实现方案**
## 简单实现方案
使用继承的解决方案如下,这种方案代码无法复用,如果两个鸭子类拥有同样的飞行方式,就有两份重复的代码。
<div align="center"> <img src="../pics//144d28a0-1dc5-4aba-8961-ced5bc88428a.jpg"/> </div><br>
**4. 设计原则**
## 设计原则
封装变化 :在这里变化的是鸭子叫和飞行的行为方式。
**封装变化** :在这里变化的是鸭子叫和飞行的行为方式。
针对接口编程,而不是针对实现编程 :变量声明的类型为父类,而不是具体的某个子类。父类中的方法实现不在父类,而是在各个子类。程序在运行时可以动态改变变量所指向的子类类型。
**针对接口编程,而不是针对实现编程** :变量声明的类型为父类,而不是具体的某个子类。父类中的方法实现不在父类,而是在各个子类。程序在运行时可以动态改变变量所指向的子类类型。
运用这一原则,将叫和飞行的行为抽象出来,实现多种不同的叫和飞行的子类,让子类去实现具体的叫和飞行方式。
<div align="center"> <img src="../pics//1c8ccf5c-7ecd-4b8a-b160-3f72a510ce26.png"/> </div><br>
多用组合,少用继承:组合也就是 HAS-A 关系,通过组合,可以在运行时动态改变实现,只要通过改变父类对象具体指向哪个子类即可。而继承就不能做到这些,继承体系在创建类时就已经确定。
**多用组合,少用继承** :组合也就是 HAS-A 关系,通过组合,可以在运行时动态改变实现,只要通过改变父类对象具体指向哪个子类即可。而继承就不能做到这些,继承体系在创建类时就已经确定。
运用这一原则,在 Duck 类中组合 FlyBehavior 和 QuackBehavior 类performQuack() 和 performFly() 方法委托给这两个类去处理。通过这种方式,一个 Duck 子类可以根据需要去初始化 FlyBehavior 和 QuackBehavior 的子类对象,并且也可以动态地进行改变。
<div align="center"> <img src="../pics//29574e6f-295c-444e-83c7-b162e8a73a83.jpg"/> </div><br>
**5. 整体设计图**
## 问题的解决方案类图
<div align="center"> <img src="../pics//d887219c-963a-4392-abe7-d3967546e96d.jpg"/> </div><br>
**6. 模式定义**
策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
**7. 实现代码**
## 代码实现
```java
public abstract class Duck {
@ -172,15 +174,15 @@ FlyBehavior.FlyWithWings
FlyBehavior.FlyNoWay
```
# 观察者模式
# 三、观察者模式
**1. 模式定义**
## 模式定义
定义了对象之间的一对多依赖当一个对象改变状态时它的所有依赖者都会收到通知并自动更新。主题Subject是被观察的对象而其所有依赖者Observer称为观察者。
<div align="center"> <img src="../pics//26cb5e7e-6fa3-44ad-854e-fe24d1a5278c.jpg"/> </div><br>
**2. 模式类图**
## 模式类图
主题具有注册和移除观察者、并通知所有注册者的功能,主题是通过维护一张观察者列表来实现这些操作的。
@ -188,19 +190,19 @@ FlyBehavior.FlyNoWay
<div align="center"> <img src="../pics//58b9926c-b56c-42f7-82e3-86aa0c164d0a.jpg"/> </div><br>
**3. 问题描述**
## 问题描述
天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。
**4. 解决方案类图**
## 问题的解决方案类图
<div align="center"> <img src="../pics//73ecb593-664e-490e-80e9-4319773113ef.png"/> </div><br>
**5. 设计原则**
## 设计原则
为交互对象之间的松耦合设计而努力:当两个对象之间松耦合,它们依然可以交互,但是不清楚彼此的细节。由于松耦合的两个对象之间互相依赖程度很低,因此系统具有弹性,能够应对变化。
**6. 实现代码**
## 代码实现
```java
public interface Subject {
@ -304,13 +306,13 @@ CurrentConditionsDisplay.update:1.0 1.0 1.0
StatisticsDisplay.update:1.0 1.0 1.0
```
# 装饰模式
# 四、装饰模式
**1. 问题描述**
## 问题描述
设计不同种类的饮料,饮料可以添加配料,比如可以添加牛奶,并且支持动态添加新配料。每增加一种配料,该饮料的价格就会增加,要求计算一种饮料的价格。
**2. 模式定义**
## 模式定义
动态地将责任附加到对象上。在扩展功能上,装饰者提供了比继承更有弹性的替代方案。
@ -318,25 +320,25 @@ StatisticsDisplay.update:1.0 1.0 1.0
<div align="center"> <img src="../pics//41a4cb30-f393-4b3b-abe4-9941ccf8fa1f.jpg"/> </div><br>
**3. 模式类图**
## 模式类图
装饰者Decorator和具体组件ConcreteComponent都继承自组件Component具体组件的方法实现不需要依赖于其它对象而装饰者组合了一个组件这样它可以装饰其它装饰者或者具体组件。所谓装饰就是把这个装饰者套在被装饰上从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的这属于它的功能然后调用被装饰者的方法实现从而也保留了被装饰者的功能。可以看到具体组件应当是装饰层次的最低层因为只有具体组件的方法实现不需要依赖于其它对象。
<div align="center"> <img src="../pics//3dc454fb-efd4-4eb8-afde-785b2182caeb.jpg"/> </div><br>
**4. 问题的解决方案类图**
## 问题的解决方案类图
<div align="center"> <img src="../pics//dac28811-79b6-4b75-bfa7-6b228e8ac3fb.png"/> </div><br>
**5. 设计原则**
## 设计原则
类应该对扩展开放,对修改关闭:也就是添加新功能时不需要修改代码。在本章问题中该原则体现在,饮料可以动态添加新的配料,而不需要去修改饮料的代码。观察则模式也符合这个原则。不可能把所有的类设计成都满足这一原则,应当把该原则应用于最有可能发生改变的地方。
**6. Java I/O 中的装饰者模式**
## Java I/O 中的装饰者模式
<div align="center"> <img src="../pics//14583c71-8f57-4939-a9fc-065469b1bb7a.png"/> </div><br>
**7. 代码实现**
## 代码实现
```java
public interface Beverage {
@ -407,15 +409,13 @@ public class StartbuzzCoffee {
3.0
```
# 工厂模式
# 五、简单工厂
## 1. 简单工厂
**1. 问题描述**
## 问题描述
Pizza 类有很多子类,要求根据不同的情况用不同的子类实例化一个 Pizza 对象。
**2. 定义**
## 模式定义
简单工厂不是设计模式,更像是一种编程习惯。它把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个子类来实例化。
@ -423,11 +423,11 @@ Pizza 类有很多子类,要求根据不同的情况用不同的子类实例
<div align="center"> <img src="../pics//ec2f0a65-82ad-4ab9-940f-70ee9f6992cc.png"/> </div><br>
**3. 问题的解决方案类图**
## 问题的解决方案类图
<div align="center"> <img src="../pics//dc3e704c-7c57-42b8-93ea-ddd068665964.jpg"/> </div><br>
**4. 代码实现**
## 代码实现
```java
public interface Pizza {
@ -483,17 +483,17 @@ public class PizzaStore {
CheesePizza
```
## 2. 工厂方法模式
# 六、工厂方法模式
**1. 问题描述**
## 问题描述
每个地区的 PizzaStore 卖的 Pizza 虽然种类相同,但是都有自己的风味。一个客户点了纽约的 cheese 种类的 Pizza 和在芝加哥点的相同种类的 Pizza 是不同的。要求设计出满足条件的 PizzaStore。
**2. 模式定义**
## 2. 模式定义
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化推迟到子类。
**3. 模式类图**
## 3. 模式类图
在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
@ -501,19 +501,19 @@ CheesePizza
<div align="center"> <img src="../pics//903093ec-acc8-4f9b-bf2c-b990b9a5390c.jpg"/> </div><br>
**4. 问题的解决方案类图**
## 4. 问题的解决方案类图
PizzaStore 有 orderPizza() 方法,顾客可以用它来下单。下单之后需要先使用 createPizza() 来制作 Pizza这里的 createPizza() 就是 factoryMethod(),不同的 PizzaStore 子类实现了不同的 createPizza()。
<div align="center"> <img src="../pics//cfb05050-47aa-4fd1-86eb-a7c86320f81b.png"/> </div><br>
**5. 设计原则**
## 5. 设计原则
依赖倒置原则:要依赖抽象,不要依赖具体类。听起来像是针对接口编程,不针对实现编程,但是这个原则说明了:不能让高层组件依赖底层组件,而且,不管高层或底层组件,两者都应该依赖于抽象。例如,下图中 Pizza 是抽象类PizzaStore 和 Pizza 子类都依赖于 Pizza 这个抽象类。
<div align="center"> <img src="../pics//ddf72ca9-c0be-49d7-ab81-57a99a974c8e.jpg"/> </div><br>
**6. 代码实现**
## 6. 代码实现
```java
public interface Pizza {
@ -609,13 +609,13 @@ NYStyleCheesePizza is making..
ChicagoStyleCheesePizza is making..
```
## 3. 抽象工厂模式
# 七、抽象工厂模式
**1. 模式定义**
## 模式定义
提供一个接口,用于创建 **相关的对象家族**
**2. 模式类图**
## 模式类图
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
@ -627,11 +627,11 @@ ChicagoStyleCheesePizza is making..
<div align="center"> <img src="../pics//0de18cdb-e974-47a3-af47-9538edafe857.png"/> </div><br>
**3. 解决方案类图**
## 解决方案类图
<div align="center"> <img src="../pics//967b2f5a-6ade-4ceb-bb41-493483fd3dff.png"/> </div><br>
**4. 代码实现**
## 代码实现
```java
public interface Dough {
@ -740,13 +740,13 @@ ThickCrustDough
MarinaraSauce
```
# 单件模式
# 八、单例模式
**1. 模式定义**
## 模式定义
确保一个类只有一个实例,并提供了一个全局访问点。
**2. 模式类图**
## 模式类图
使用一个私有构造器、一个私有静态变量以及一个公有静态函数来实现。
@ -754,7 +754,7 @@ MarinaraSauce
<div align="center"> <img src="../pics//da5dbeae-f247-400b-84d8-af48f0241bc9.png"/> </div><br>
**3. 懒汉式-线程不安全**
## 懒汉式-线程不安全
以下实现中,私有静态变量 uniqueInstance 被延迟化实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance从而节约资源。
@ -777,7 +777,7 @@ public class Singleton {
}
```
**4. 懒汉式-线程安全**
## 懒汉式-线程安全
只需要对 `getUniqueInstance()` 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了对 uniqueInstance 进行多次实例化的问题。
@ -792,7 +792,7 @@ public static synchronized Singleton getUniqueInstance() {
}
```
**5. 饿汉式-线程安全**
## 饿汉式-线程安全
线程不安全问题主要是由于 uniqueInstance 被实例化了多次,如果 uniqueInstance 采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全问题。但是直接实例化的方式也丢失了延迟实例化带来的节约资源的优势。
@ -800,7 +800,7 @@ public static synchronized Singleton getUniqueInstance() {
private static Singleton uniqueInstance = new Singleton();
```
**6. 双重校验锁-线程安全**
## 双重校验锁-线程安全
uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行。也就是说,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
@ -837,9 +837,9 @@ if (uniqueInstance == null) {
}
```
# 命令模式
# 九、命令模式
**1. 问题描述**
## 问题描述
设计一个遥控器,它有很多按钮,每个按钮可以发起一个命令,命令会让一个家电完成相应操作。有非常多的家电,并且之后会增加家电。
@ -849,11 +849,11 @@ if (uniqueInstance == null) {
<div align="center"> <img src="../pics//5b832bde-d05e-42db-b648-42e274571ad9.jpg" width="700"/> </div><br>
**2. 模式定义**
## 模式定义
将命令封装成对象,以便使用不同的命令来参数化其它对象。
**3. 问题的解决方案类图**
## 问题的解决方案类图
- RemoteControl 是遥控器,它可以为每个按钮设置命令对象,并且执行命令。
@ -865,11 +865,11 @@ if (uniqueInstance == null) {
<div align="center"> <img src="../pics//b7b1f5c6-ff8a-4353-8060-44bbc4b9e02e.jpg" width="1000"/> </div><br>
**4. 模式类图**
## 模式类图
<div align="center"> <img src="../pics//26ccd069-55ec-4a28-aeb3-025e39e5810f.jpg" width="1000"/> </div><br>
**5. 代码实现**
## 代码实现
```java
public interface Command {
@ -948,31 +948,31 @@ public class RemoteLoader {
Light is on!
```
# 适配器模式
# 十、适配器模式
**1. 模式定义**
## 模式定义
将一个类的接口,转换为客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。
<div align="center"> <img src="../pics//c484b07d-be3d-4699-9e28-f035de8a274c.jpg" width="800"/> </div><br>
**2. 模式类图**
## 模式类图
适配器Adapter组合一个适配者AdapteeAdapter 把操作委托给 Adaptee。
<div align="center"> <img src="../pics//253bd869-ea48-4092-9aed-6906ccb2f3b0.jpg"/> </div><br>
**3. 问题描述**
## 问题描述
鸭子Duck和火鸡Turkey拥有不同的叫声Duck 的叫声调用 quack() 方法,而 Turkey 调用 gobble() 方法。
要求将 Turkey 的 gobble() 方法适配成 Duck 的 quack() 方法,从而让火鸡冒充鸭子!
**4. 解决方案类图**
## 问题的解决方案类图
<div align="center"> <img src="../pics//b8ceb9db-180e-4d01-932c-593fa2a6f515.jpg"/> </div><br>
**5. 代码实现**
## 代码实现
```java
public interface Duck {
@ -1026,69 +1026,69 @@ public class DuckTestDrive {
gobble!
```
# 外观模式
# 十、外观模式
**1. 模式定义**
## 模式定义
提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。
**2. 模式类图**
## 模式类图
<div align="center"> <img src="../pics//78f2314e-2643-41df-8f3d-b7e28294094b.jpg" width="1000"/> </div><br>
**3. 问题描述**
## 问题描述
家庭影院中有众多电器,当要进行观看电影时需要对很多电器进行操作。要求简化这些操作,使得家庭影院类只提供一个简化的接口,例如提供一个看电影相关的接口。
<div align="center"> <img src="../pics//106f5585-b2e7-4718-be5d-3b322d1ef42a.jpg" width="500"/> </div><br>
**4. 解决方案类图**
## 解决方案类图
<div align="center"> <img src="../pics//a0339a9f-f44f-4e37-a37f-169bc735536d.jpg"/> </div><br>
**5. 设计原则**
## 设计原则
最少知识原则:只和你的密友谈话。也就是客户对象所需要交互的对象应当尽可能少。
**最少知识原则** :只和你的密友谈话。也就是客户对象所需要交互的对象应当尽可能少。
**6. 代码实现**
## 代码实现
过于简单,无实现。
# 模板方法模式
# 十一、模板方法模式
**1. 模式定义**
## 模式定义
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。
模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
**2. 模式类图**
## 模式类图
模板方法 templateMethod() 定义了算法的骨架,确定了 primitiveOperation1() 和 primitiveOperation2() 方法执行的顺序,而 primitiveOperation1() 和 primitiveOperation2() 让子类去实现。
<div align="center"> <img src="../pics//87ffaf7f-4aa5-4da0-af84-994de62fa440.jpg"/> </div><br>
**3. 问题描述**
## 问题描述
冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。
<div align="center"> <img src="../pics//d8f873fc-00bc-41ee-a87c-c1b4c0172844.png"/> </div><br>
**4. 问题的解决方案类图**
## 问题的解决方案类图
prepareRecipe() 方法就是模板方法,它确定了其它四个方法的具体执行步骤。其中 brew() 和 addCondiments() 方法在子类中实现。
<div align="center"> <img src="../pics//aa20c123-b6b5-432a-83d3-45dc39172192.jpg"/> </div><br>
**5. 设计原则**
## 设计原则
好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。这一原则可以防止依赖腐败,即防止高层组件依赖低层组件,低层组件又依赖高层组件。该原则在模板方法的体现为,只有父类会调用子类,子类不会调用父类。
**好莱坞原则** :别调用(打电话给)我们,我们会调用(打电话给)你。这一原则可以防止依赖腐败,即防止高层组件依赖低层组件,低层组件又依赖高层组件。该原则在模板方法的体现为,只有父类会调用子类,子类不会调用父类。
**6. 钩子**
## 钩子
某些步骤在不同实现中可有可无,可以先定义一个什么都不做的方法,把它加到模板方法中,如果子类需要它就覆盖默认实现并加上自己的实现。
**7. 代码实现**
## 代码实现
```java
public abstract class CaffeineBeverage {
@ -1168,13 +1168,13 @@ pourInCup
Tea.addCondiments
```
# 迭代器模式
# 十二、迭代器模式
**1. 模式定义**
## 模式定义
提供顺序访问一个聚合对象中的各个元素的方法,而又不暴露聚合对象内部的表示。
**2. 模式类图**
## 模式类图
- Aggregate 是聚合类,其中 createIterator() 方法可以产生一个 Iterator
@ -1184,7 +1184,7 @@ Tea.addCondiments
<div align="center"> <img src="../pics//439deca7-fed0-4c89-87e5-7088d10f1fdb.jpg"/> </div><br>
**3. 代码实现**
## 代码实现
```java
public class Aggregate {
@ -1258,7 +1258,7 @@ public class Client {
9
```
**4. Java 内置的迭代器**
## Java 内置的迭代器
需要让聚合类实现 Iterable 接口,该接口有一个 iterator() 方法会返回一个 Iterator 对象。
@ -1320,19 +1320,19 @@ public class Client {
}
```
# 组合模式
# 十三、组合模式
**1. 设计原则**
## 设计原则
一个类应该只有一个引起它改变的原因。
**2. 模式定义**
## 模式定义
允许将对象组合成树形结构来表现“整体/部分”关系。
组合能让客户以一致的方式处理个别对象以及组合对象。
**3. 模式类图**
## 模式类图
组件Component类是组合类Composite和叶子类Leaf的父类可以把组合类看成是树的中间节点。
@ -1340,7 +1340,7 @@ public class Client {
<div align="center"> <img src="../pics//cf08a51d-14c0-4bfc-863b-c8672d9c2b02.jpg"/> </div><br>
**4. 代码实现**
## 代码实现
```java
public abstract class Component {
@ -1441,19 +1441,19 @@ Composite:root
--left:3
```
# 状态模式
# 十四、状态模式
**1. 模式定义**
## 模式定义
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。
**2. 模式类图**
## 模式类图
Context 的 request() 方法委托给 State 对象去处理。当 Context 组合的 State 对象发生改变时,它的行为也就发生了改变。
<div align="center"> <img src="../pics//c28fd93a-0d55-4a19-810f-72652feee00d.jpg"/> </div><br>
**3. 与策略模式的比较**
## 与策略模式的比较
状态模式的类图和策略模式一样,并且都是能够动态改变对象的行为。
@ -1463,13 +1463,13 @@ Context 的 request() 方法委托给 State 对象去处理。当 Context 组合
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 需要使用哪个算法。
**4. 问题描述**
## 问题描述
糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。
<div align="center"> <img src="../pics//f7d880c9-740a-4a16-ac6d-be502281b4b2.jpg"/> </div><br>
**5. 直接解决方案**
## 直接解决方案
在糖果机的每个操作函数里面,判断当前的状态,根据不同的状态进行不同的处理,并且发生不同的状态转移。
@ -1477,7 +1477,7 @@ Context 的 request() 方法委托给 State 对象去处理。当 Context 组合
<div align="center"> <img src="../pics//62ebbb63-8fd7-4488-a866-76a9dc911662.png"/> </div><br>
**6 代码实现**
## 代码实现
糖果销售机即 Context。
@ -1763,34 +1763,36 @@ You turned, but there are no gumballs
No gumball dispensed
```
# 代理模式
# 十五、代理模式
# 复合模式
# 十六、MVC
## MVC
**传统 MVC**
## 传统 MVC
视图使用组合模式,模型使用了观察者模式,控制器使用了策略模式。
<div align="center"> <img src="../pics//4f67611d-492f-4958-9fa0-4948010e345f.jpg"/> </div><br>
**Web 中的 MVC**
## Web 中的 MVC
模式不再使用观察者模式。
<div align="center"> <img src="../pics//1dd56e61-2970-4d27-97c2-6e81cee86978.jpg"/> </div><br>
# 与设计模式相处
# 十七、与设计模式相处
定义:在某情境下,针对某问题的某种解决方案。
## 定义
在某情境下,针对某问题的某种解决方案。
## 何时使用
过度使用设计模式可能导致代码被过度工程化,应该总是用最简单的解决方案完成工作,并在真正需要模式的地方才使用它。
反模式:不好的解决方案来解决一个问题。主要作用是为了警告人们不要使用这些解决方案。
## 反模式
模式分类:
不好的解决方案来解决一个问题。主要作用是为了警告人们不要使用这些解决方案。
## 模式分类
<div align="center"> <img src="../pics//524a237c-ffd7-426f-99c2-929a6bf4c847.jpg"/> </div><br>
# 剩下的模式