设计模式.md 78.0 KB
Newer Older
C
CyC2018 已提交
1
[⭐️ 面试进阶专栏 ⭐️](https://xiaozhuanlan.com/CyC2018)
C
CyC2018 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
<!-- GFM-TOC -->
* [一、概述](#一概述)
* [二、创建型](#二创建型)
    * [1. 单例(Singleton)](#1-单例singleton)
    * [2. 简单工厂(Simple Factory)](#2-简单工厂simple-factory)
    * [3. 工厂方法(Factory Method)](#3-工厂方法factory-method)
    * [4. 抽象工厂(Abstract Factory)](#4-抽象工厂abstract-factory)
    * [5. 生成器(Builder)](#5-生成器builder)
    * [6. 原型模式(Prototype)](#6-原型模式prototype)
* [三、行为型](#三行为型)
    * [1. 责任链(Chain Of Responsibility)](#1-责任链chain-of-responsibility)
    * [2. 命令(Command)](#2-命令command)
    * [3. 解释器(Interpreter)](#3-解释器interpreter)
    * [4. 迭代器(Iterator)](#4-迭代器iterator)
    * [5. 中介者(Mediator)](#5-中介者mediator)
    * [6. 备忘录(Memento)](#6-备忘录memento)
    * [7. 观察者(Observer)](#7-观察者observer)
    * [8. 状态(State)](#8-状态state)
    * [9. 策略(Strategy)](#9-策略strategy)
    * [10. 模板方法(Template Method)](#10-模板方法template-method)
    * [11. 访问者(Visitor)](#11-访问者visitor)
    * [12. 空对象(Null)](#12-空对象null)
* [四、结构型](#四结构型)
    * [1. 适配器(Adapter)](#1-适配器adapter)
    * [2. 桥接(Bridge)](#2-桥接bridge)
    * [3. 组合(Composite)](#3-组合composite)
    * [4. 装饰(Decorator)](#4-装饰decorator)
    * [5. 外观(Facade)](#5-外观facade)
    * [6. 享元(Flyweight)](#6-享元flyweight)
    * [7. 代理(Proxy)](#7-代理proxy)
* [参考资料](#参考资料)
<!-- GFM-TOC -->


# 一、概述
C
CyC2018 已提交
37

C
CyC2018 已提交
38
设计模式是解决问题的方案,学习现有的设计模式可以做到经验复用。
C
CyC2018 已提交
39 40 41

拥有设计模式词汇,在沟通时就能用更少的词汇来讨论,并且不需要了解底层细节。

C
CyC2018 已提交
42
[源码以及 UML 图](https://github.com/CyC2018/Design-Pattern-Java)
C
CyC2018 已提交
43

C
CyC2018 已提交
44
# 二、创建型
C
CyC2018 已提交
45

C
CyC2018 已提交
46
## 1. 单例(Singleton)
C
CyC2018 已提交
47

C
CyC2018 已提交
48
### Intent
C
CyC2018 已提交
49

C
CyC2018 已提交
50 51
确保一个类只有一个实例,并提供该实例的全局访问点。

C
CyC2018 已提交
52
### Class Diagram
C
CyC2018 已提交
53 54 55 56 57

使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。

私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。

C
CyC2018 已提交
58
<div align="center"> <img src="pics/562f2844-d77c-40e0-887a-28a7128abd42.png"/> </div><br>
C
CyC2018 已提交
59

C
CyC2018 已提交
60
### Implementation
C
CyC2018 已提交
61

C
CyC2018 已提交
62
#### Ⅰ 懒汉式-线程不安全
C
CyC2018 已提交
63

C
CyC2018 已提交
64
以下实现中,私有静态变量 uniqueInstance 被延迟实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance,从而节约资源。
C
CyC2018 已提交
65

C
CyC2018 已提交
66
这个实现在多线程环境下是不安全的,如果多个线程能够同时进入 `if (uniqueInstance == null)` ,并且此时 uniqueInstance 为 null,那么会有多个线程执行 `uniqueInstance = new Singleton();` 语句,这将导致实例化多次 uniqueInstance。
C
CyC2018 已提交
67 68

```java
C
CyC2018 已提交
69
public class Singleton {
C
CyC2018 已提交
70

C
CyC2018 已提交
71
    private static Singleton uniqueInstance;
C
CyC2018 已提交
72

C
CyC2018 已提交
73 74
    private Singleton() {
    }
C
CyC2018 已提交
75

C
CyC2018 已提交
76 77 78 79 80 81
    public static Singleton getUniqueInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
C
CyC2018 已提交
82 83 84
}
```

C
CyC2018 已提交
85
#### Ⅱ 饿汉式-线程安全
C
CyC2018 已提交
86

C
CyC2018 已提交
87
线程不安全问题主要是由于 uniqueInstance 被实例化多次,采取直接实例化 uniqueInstance 的方式就不会产生线程不安全问题。
C
CyC2018 已提交
88

C
CyC2018 已提交
89
但是直接实例化的方式也丢失了延迟实例化带来的节约资源的好处。
C
CyC2018 已提交
90 91

```java
C
CyC2018 已提交
92
private static Singleton uniqueInstance = new Singleton();
C
CyC2018 已提交
93 94
```

C
CyC2018 已提交
95
#### Ⅲ 懒汉式-线程安全
C
CyC2018 已提交
96

C
CyC2018 已提交
97
只需要对 getUniqueInstance() 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了实例化多次 uniqueInstance。
C
CyC2018 已提交
98

C
CyC2018 已提交
99
但是当一个线程进入该方法之后,其它试图进入该方法的线程都必须等待,即使 uniqueInstance 已经被实例化了。这会让线程阻塞时间过长,因此该方法有性能问题,不推荐使用。
C
CyC2018 已提交
100 101

```java
C
CyC2018 已提交
102 103 104 105 106
public static synchronized Singleton getUniqueInstance() {
    if (uniqueInstance == null) {
        uniqueInstance = new Singleton();
    }
    return uniqueInstance;
C
CyC2018 已提交
107
}
C
CyC2018 已提交
108 109
```

C
CyC2018 已提交
110
#### Ⅳ 双重校验锁-线程安全
C
CyC2018 已提交
111

C
CyC2018 已提交
112
uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
C
CyC2018 已提交
113

C
CyC2018 已提交
114
双重校验锁先判断 uniqueInstance 是否已经被实例化,如果没有被实例化,那么才对实例化语句进行加锁。
C
CyC2018 已提交
115 116

```java
C
CyC2018 已提交
117
public class Singleton {
C
CyC2018 已提交
118

C
CyC2018 已提交
119
    private volatile static Singleton uniqueInstance;
C
CyC2018 已提交
120

C
CyC2018 已提交
121 122
    private Singleton() {
    }
C
CyC2018 已提交
123

C
CyC2018 已提交
124 125 126 127 128 129 130 131 132 133
    public static Singleton getUniqueInstance() {
        if (uniqueInstance == null) {
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
C
CyC2018 已提交
134 135 136
}
```

C
CyC2018 已提交
137
考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程都执行了 if 语句,那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 `uniqueInstance = new Singleton();` 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句。
C
CyC2018 已提交
138 139

```java
C
CyC2018 已提交
140 141 142 143
if (uniqueInstance == null) {
    synchronized (Singleton.class) {
        uniqueInstance = new Singleton();
    }
C
CyC2018 已提交
144 145 146
}
```

C
CyC2018 已提交
147
uniqueInstance 采用 volatile 关键字修饰也是很有必要的, `uniqueInstance = new Singleton();` 这段代码其实是分为三步执行:
C
CyC2018 已提交
148

C
CyC2018 已提交
149 150 151
1. 为 uniqueInstance 分配内存空间
2. 初始化 uniqueInstance
3. 将 uniqueInstance 指向分配的内存地址
C
CyC2018 已提交
152

C
CyC2018 已提交
153
但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T<sub>1</sub> 执行了 1 和 3,此时 T<sub>2</sub> 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance,但此时 uniqueInstance 还未被初始化。
C
CyC2018 已提交
154

C
CyC2018 已提交
155
使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。
C
CyC2018 已提交
156

C
CyC2018 已提交
157
#### Ⅴ 静态内部类实现
158

C
CyC2018 已提交
159
当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 `getUniqueInstance()` 方法从而触发 `SingletonHolder.INSTANCE` 时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
160

C
CyC2018 已提交
161
这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。
C
CyC2018 已提交
162

C
CyC2018 已提交
163
```java
C
CyC2018 已提交
164
public class Singleton {
165

C
CyC2018 已提交
166 167
    private Singleton() {
    }
168

C
CyC2018 已提交
169 170 171
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
172

C
CyC2018 已提交
173 174 175
    public static Singleton getUniqueInstance() {
        return SingletonHolder.INSTANCE;
    }
176 177 178
}
```

C
CyC2018 已提交
179
#### Ⅵ 枚举实现
P
peierlong 已提交
180

C
CyC2018 已提交
181
```java
C
CyC2018 已提交
182
public enum Singleton {
P
peierlong 已提交
183

C
CyC2018 已提交
184
    INSTANCE;
P
peierlong 已提交
185

C
CyC2018 已提交
186
    private String objName;
P
peierlong 已提交
187

C
CyC2018 已提交
188

C
CyC2018 已提交
189 190 191
    public String getObjName() {
        return objName;
    }
P
peierlong 已提交
192

C
CyC2018 已提交
193

C
CyC2018 已提交
194 195 196
    public void setObjName(String objName) {
        this.objName = objName;
    }
P
peierlong 已提交
197

C
CyC2018 已提交
198

C
CyC2018 已提交
199
    public static void main(String[] args) {
C
CyC2018 已提交
200

C
CyC2018 已提交
201 202 203 204 205 206 207 208
        // 单例测试
        Singleton firstSingleton = Singleton.INSTANCE;
        firstSingleton.setObjName("firstName");
        System.out.println(firstSingleton.getObjName());
        Singleton secondSingleton = Singleton.INSTANCE;
        secondSingleton.setObjName("secondName");
        System.out.println(firstSingleton.getObjName());
        System.out.println(secondSingleton.getObjName());
P
peierlong 已提交
209

C
CyC2018 已提交
210 211 212 213 214 215 216 217 218 219
        // 反射获取实例测试
        try {
            Singleton[] enumConstants = Singleton.class.getEnumConstants();
            for (Singleton enumConstant : enumConstants) {
                System.out.println(enumConstant.getObjName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
C
CyC2018 已提交
220
}
C
CyC2018 已提交
221
```
P
peierlong 已提交
222

C
CyC2018 已提交
223 224 225 226 227 228 229
```html
firstName
secondName
secondName
secondName
```

C
CyC2018 已提交
230
该实现在多次序列化再进行反序列化之后,不会得到多个实例。而其它实现需要使用 transient 修饰所有字段,并且实现序列化和反序列化的方法。
P
peierlong 已提交
231

C
CyC2018 已提交
232
该实现可以防止反射攻击。在其它实现中,通过 setAccessible() 方法可以将私有构造函数的访问级别设置为 public,然后调用构造函数从而实例化对象,如果要防止这种攻击,需要在构造函数中添加防止多次实例化的代码。该实现是由 JVM 保证只会实例化一次,因此不会出现上述的反射攻击。
P
peierlong 已提交
233

C
CyC2018 已提交
234
### Examples
C
crossoverJie 已提交
235

C
CyC2018 已提交
236 237 238 239
- Logger Classes
- Configuration Classes
- Accesing resources in shared mode
- Factories implemented as Singletons
C
crossoverJie 已提交
240

C
CyC2018 已提交
241
### JDK
C
crossoverJie 已提交
242

C
CyC2018 已提交
243 244 245
- [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
- [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--)
- [java.lang.System#getSecurityManager()](http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--)
C
crossoverJie 已提交
246

C
CyC2018 已提交
247
## 2. 简单工厂(Simple Factory)
C
CyC2018 已提交
248

C
CyC2018 已提交
249
### Intent
C
CyC2018 已提交
250

C
CyC2018 已提交
251
在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。
C
CyC2018 已提交
252

C
CyC2018 已提交
253
### Class Diagram
C
CyC2018 已提交
254

C
CyC2018 已提交
255
简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化。
C
CyC2018 已提交
256

C
CyC2018 已提交
257
这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。客户类往往有多个,如果不使用简单工厂,那么所有的客户类都要知道所有子类的细节。而且一旦子类发生改变,例如增加子类,那么所有的客户类都要进行修改。
C
CyC2018 已提交
258

C
CyC2018 已提交
259
<div align="center"> <img src="pics/c79da808-0f28-4a36-bc04-33ccc5b83c13.png"/> </div><br>
C
CyC2018 已提交
260

C
CyC2018 已提交
261
### Implementation
C
CyC2018 已提交
262 263

```java
C
CyC2018 已提交
264
public interface Product {
C
CyC2018 已提交
265 266 267 268
}
```

```java
C
CyC2018 已提交
269
public class ConcreteProduct implements Product {
C
CyC2018 已提交
270 271 272 273
}
```

```java
C
CyC2018 已提交
274
public class ConcreteProduct1 implements Product {
C
CyC2018 已提交
275 276 277 278
}
```

```java
C
CyC2018 已提交
279
public class ConcreteProduct2 implements Product {
C
CyC2018 已提交
280 281 282
}
```

C
CyC2018 已提交
283
以下的 Client 类包含了实例化的代码,这是一种错误的实现。如果在客户类中存在这种实例化代码,就需要考虑将代码放到简单工厂中。
C
CyC2018 已提交
284 285

```java
C
CyC2018 已提交
286
public class Client {
C
CyC2018 已提交
287

C
CyC2018 已提交
288 289 290 291 292 293 294 295 296 297 298 299
    public static void main(String[] args) {
        int type = 1;
        Product product;
        if (type == 1) {
            product = new ConcreteProduct1();
        } else if (type == 2) {
            product = new ConcreteProduct2();
        } else {
            product = new ConcreteProduct();
        }
        // do something with the product
    }
C
CyC2018 已提交
300 301 302
}
```

C
CyC2018 已提交
303
以下的 SimpleFactory 是简单工厂实现,它被所有需要进行实例化的客户类调用。
C
CyC2018 已提交
304

C
CyC2018 已提交
305
```java
C
CyC2018 已提交
306
public class SimpleFactory {
C
CyC2018 已提交
307

C
CyC2018 已提交
308 309 310 311 312 313 314 315
    public Product createProduct(int type) {
        if (type == 1) {
            return new ConcreteProduct1();
        } else if (type == 2) {
            return new ConcreteProduct2();
        }
        return new ConcreteProduct();
    }
C
CyC2018 已提交
316 317 318 319
}
```

```java
C
CyC2018 已提交
320
public class Client {
C
CyC2018 已提交
321

C
CyC2018 已提交
322 323 324 325 326
    public static void main(String[] args) {
        SimpleFactory simpleFactory = new SimpleFactory();
        Product product = simpleFactory.createProduct(1);
        // do something with the product
    }
C
CyC2018 已提交
327 328 329
}
```

C
CyC2018 已提交
330
## 3. 工厂方法(Factory Method)
C
CyC2018 已提交
331

C
CyC2018 已提交
332
### Intent
C
CyC2018 已提交
333

C
CyC2018 已提交
334
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。
C
CyC2018 已提交
335

C
CyC2018 已提交
336
### Class Diagram
C
CyC2018 已提交
337 338 339

在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。

C
CyC2018 已提交
340
下图中,Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
C
CyC2018 已提交
341

C
CyC2018 已提交
342
<div align="center"> <img src="pics/1818e141-8700-4026-99f7-900a545875f5.png"/> </div><br>
C
CyC2018 已提交
343

C
CyC2018 已提交
344
### Implementation
C
CyC2018 已提交
345 346

```java
C
CyC2018 已提交
347 348 349 350 351 352
public abstract class Factory {
    abstract public Product factoryMethod();
    public void doSomething() {
        Product product = factoryMethod();
        // do something with the product
    }
C
CyC2018 已提交
353 354 355 356
}
```

```java
C
CyC2018 已提交
357 358 359 360
public class ConcreteFactory extends Factory {
    public Product factoryMethod() {
        return new ConcreteProduct();
    }
C
CyC2018 已提交
361 362 363 364
}
```

```java
C
CyC2018 已提交
365 366 367 368
public class ConcreteFactory1 extends Factory {
    public Product factoryMethod() {
        return new ConcreteProduct1();
    }
C
CyC2018 已提交
369 370 371 372
}
```

```java
C
CyC2018 已提交
373 374 375 376
public class ConcreteFactory2 extends Factory {
    public Product factoryMethod() {
        return new ConcreteProduct2();
    }
C
CyC2018 已提交
377 378 379
}
```

C
CyC2018 已提交
380
### JDK
C
CyC2018 已提交
381

C
CyC2018 已提交
382 383 384 385 386 387 388
- [java.util.Calendar](http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--)
- [java.util.ResourceBundle](http://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-)
- [java.text.NumberFormat](http://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--)
- [java.nio.charset.Charset](http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-)
- [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-)
- [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-)
- [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--)
C
CyC2018 已提交
389

C
CyC2018 已提交
390
## 4. 抽象工厂(Abstract Factory)
C
CyC2018 已提交
391

C
CyC2018 已提交
392
### Intent
C
CyC2018 已提交
393

C
CyC2018 已提交
394
提供一个接口,用于创建  **相关的对象家族**
C
CyC2018 已提交
395

C
CyC2018 已提交
396
### Class Diagram
C
CyC2018 已提交
397

C
CyC2018 已提交
398
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
C
CyC2018 已提交
399

C
CyC2018 已提交
400
抽象工厂模式用到了工厂方法模式来创建单一对象,AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂方法模式的定义。
C
CyC2018 已提交
401

C
CyC2018 已提交
402
至于创建对象的家族这一概念是在 Client 体现,Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client 需要同时创建出这两个对象。
C
CyC2018 已提交
403

C
CyC2018 已提交
404
从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂方法模式使用了继承。
C
CyC2018 已提交
405

C
CyC2018 已提交
406
<div align="center"> <img src="pics/8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png"/> </div><br>
C
CyC2018 已提交
407

C
CyC2018 已提交
408
### Implementation
C
CyC2018 已提交
409 410

```java
C
CyC2018 已提交
411
public class AbstractProductA {
C
CyC2018 已提交
412 413 414 415
}
```

```java
C
CyC2018 已提交
416
public class AbstractProductB {
C
CyC2018 已提交
417 418 419 420
}
```

```java
C
CyC2018 已提交
421
public class ProductA1 extends AbstractProductA {
C
CyC2018 已提交
422 423 424 425
}
```

```java
C
CyC2018 已提交
426
public class ProductA2 extends AbstractProductA {
C
CyC2018 已提交
427 428 429 430
}
```

```java
C
CyC2018 已提交
431
public class ProductB1 extends AbstractProductB {
C
CyC2018 已提交
432 433 434 435
}
```

```java
C
CyC2018 已提交
436
public class ProductB2 extends AbstractProductB {
C
CyC2018 已提交
437 438 439 440
}
```

```java
C
CyC2018 已提交
441 442 443
public abstract class AbstractFactory {
    abstract AbstractProductA createProductA();
    abstract AbstractProductB createProductB();
C
CyC2018 已提交
444 445 446 447
}
```

```java
C
CyC2018 已提交
448 449 450 451
public class ConcreteFactory1 extends AbstractFactory {
    AbstractProductA createProductA() {
        return new ProductA1();
    }
C
CyC2018 已提交
452

C
CyC2018 已提交
453 454 455
    AbstractProductB createProductB() {
        return new ProductB1();
    }
C
CyC2018 已提交
456 457 458 459
}
```

```java
C
CyC2018 已提交
460 461 462 463
public class ConcreteFactory2 extends AbstractFactory {
    AbstractProductA createProductA() {
        return new ProductA2();
    }
C
CyC2018 已提交
464

C
CyC2018 已提交
465 466 467
    AbstractProductB createProductB() {
        return new ProductB2();
    }
C
CyC2018 已提交
468 469 470 471
}
```

```java
C
CyC2018 已提交
472 473 474 475 476 477 478
public class Client {
    public static void main(String[] args) {
        AbstractFactory abstractFactory = new ConcreteFactory1();
        AbstractProductA productA = abstractFactory.createProductA();
        AbstractProductB productB = abstractFactory.createProductB();
        // do something with productA and productB
    }
C
CyC2018 已提交
479 480 481
}
```

C
CyC2018 已提交
482
### JDK
C
CyC2018 已提交
483

C
CyC2018 已提交
484 485 486
- [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
- [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
- [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
C
CyC2018 已提交
487

C
CyC2018 已提交
488
## 5. 生成器(Builder)
C
CyC2018 已提交
489

C
CyC2018 已提交
490
### Intent
C
CyC2018 已提交
491

C
CyC2018 已提交
492
封装一个对象的构造过程,并允许按步骤构造。
C
CyC2018 已提交
493

C
CyC2018 已提交
494
### Class Diagram
C
CyC2018 已提交
495

C
CyC2018 已提交
496
<div align="center"> <img src="pics/13b0940e-d1d7-4b17-af4f-b70cb0a75e08.png"/> </div><br>
C
CyC2018 已提交
497

C
CyC2018 已提交
498
### Implementation
C
CyC2018 已提交
499

C
CyC2018 已提交
500
以下是一个简易的 StringBuilder 实现,参考了 JDK 1.8 源码。
C
CyC2018 已提交
501 502

```java
C
CyC2018 已提交
503 504
public class AbstractStringBuilder {
    protected char[] value;
C
CyC2018 已提交
505

C
CyC2018 已提交
506
    protected int count;
C
CyC2018 已提交
507

C
CyC2018 已提交
508 509 510 511
    public AbstractStringBuilder(int capacity) {
        count = 0;
        value = new char[capacity];
    }
C
CyC2018 已提交
512

C
CyC2018 已提交
513 514 515 516 517
    public AbstractStringBuilder append(char c) {
        ensureCapacityInternal(count + 1);
        value[count++] = c;
        return this;
    }
C
CyC2018 已提交
518

C
CyC2018 已提交
519 520 521 522 523
    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0)
            expandCapacity(minimumCapacity);
    }
C
CyC2018 已提交
524

C
CyC2018 已提交
525 526 527 528 529 530 531 532 533 534 535
    void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }
C
CyC2018 已提交
536 537 538 539
}
```

```java
C
CyC2018 已提交
540 541 542 543
public class StringBuilder extends AbstractStringBuilder {
    public StringBuilder() {
        super(16);
    }
C
CyC2018 已提交
544

C
CyC2018 已提交
545 546 547 548 549
    @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }
C
CyC2018 已提交
550 551 552 553
}
```

```java
C
CyC2018 已提交
554 555 556 557 558 559 560 561 562
public class Client {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        final int count = 26;
        for (int i = 0; i < count; i++) {
            sb.append((char) ('a' + i));
        }
        System.out.println(sb.toString());
    }
C
CyC2018 已提交
563 564 565 566 567 568
}
```

```html
abcdefghijklmnopqrstuvwxyz
```
C
CyC2018 已提交
569

C
CyC2018 已提交
570
### JDK
C
CyC2018 已提交
571

C
CyC2018 已提交
572 573 574 575 576
- [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)
- [java.nio.ByteBuffer](http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte-)
- [java.lang.StringBuffer](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html#append-boolean-)
- [java.lang.Appendable](http://docs.oracle.com/javase/8/docs/api/java/lang/Appendable.html)
- [Apache Camel builders](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder)
C
CyC2018 已提交
577

C
CyC2018 已提交
578
## 6. 原型模式(Prototype)
C
CyC2018 已提交
579

C
CyC2018 已提交
580
### Intent
C
CyC2018 已提交
581

C
CyC2018 已提交
582 583
使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。

C
CyC2018 已提交
584
### Class Diagram
C
CyC2018 已提交
585

C
CyC2018 已提交
586
<div align="center"> <img src="pics/a40661e4-1a71-46d2-a158-ff36f7fc3331.png"/> </div><br>
C
CyC2018 已提交
587

C
CyC2018 已提交
588
### Implementation
C
CyC2018 已提交
589 590

```java
C
CyC2018 已提交
591 592
public abstract class Prototype {
    abstract Prototype myClone();
C
CyC2018 已提交
593 594 595 596
}
```

```java
C
CyC2018 已提交
597
public class ConcretePrototype extends Prototype {
C
CyC2018 已提交
598

C
CyC2018 已提交
599
    private String filed;
C
CyC2018 已提交
600

C
CyC2018 已提交
601 602 603
    public ConcretePrototype(String filed) {
        this.filed = filed;
    }
C
CyC2018 已提交
604

C
CyC2018 已提交
605 606 607 608
    @Override
    Prototype myClone() {
        return new ConcretePrototype(filed);
    }
C
CyC2018 已提交
609

C
CyC2018 已提交
610 611 612 613
    @Override
    public String toString() {
        return filed;
    }
C
CyC2018 已提交
614 615 616 617
}
```

```java
C
CyC2018 已提交
618 619 620 621 622 623
public class Client {
    public static void main(String[] args) {
        Prototype prototype = new ConcretePrototype("abc");
        Prototype clone = prototype.myClone();
        System.out.println(clone.toString());
    }
C
CyC2018 已提交
624 625 626 627 628 629
}
```

```html
abc
```
C
CyC2018 已提交
630

C
CyC2018 已提交
631
### JDK
C
CyC2018 已提交
632

C
CyC2018 已提交
633
- [java.lang.Object#clone()](http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone%28%29)
C
CyC2018 已提交
634

C
CyC2018 已提交
635
# 三、行为型
C
CyC2018 已提交
636

C
CyC2018 已提交
637
## 1. 责任链(Chain Of Responsibility)
C
CyC2018 已提交
638

C
CyC2018 已提交
639
### Intent
C
CyC2018 已提交
640

C
CyC2018 已提交
641
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
C
CyC2018 已提交
642

C
CyC2018 已提交
643
### Class Diagram
C
CyC2018 已提交
644

C
CyC2018 已提交
645
- Handler:定义处理请求的接口,并且实现后继链(successor)
C
CyC2018 已提交
646

C
CyC2018 已提交
647
<div align="center"> <img src="pics/691f11eb-31a7-46be-9de1-61f433c4b3c7.png"/> </div><br>
C
CyC2018 已提交
648

C
CyC2018 已提交
649
### Implementation
C
CyC2018 已提交
650 651

```java
C
CyC2018 已提交
652
public abstract class Handler {
C
CyC2018 已提交
653

C
CyC2018 已提交
654
    protected Handler successor;
C
CyC2018 已提交
655

C
CyC2018 已提交
656

C
CyC2018 已提交
657 658 659
    public Handler(Handler successor) {
        this.successor = successor;
    }
C
CyC2018 已提交
660

C
CyC2018 已提交
661

C
CyC2018 已提交
662
    protected abstract void handleRequest(Request request);
C
CyC2018 已提交
663 664 665 666
}
```

```java
C
CyC2018 已提交
667
public class ConcreteHandler1 extends Handler {
C
CyC2018 已提交
668

C
CyC2018 已提交
669 670 671
    public ConcreteHandler1(Handler successor) {
        super(successor);
    }
C
CyC2018 已提交
672

C
CyC2018 已提交
673

C
CyC2018 已提交
674 675 676 677 678 679 680 681 682 683
    @Override
    protected void handleRequest(Request request) {
        if (request.getType() == RequestType.TYPE1) {
            System.out.println(request.getName() + " is handle by ConcreteHandler1");
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
C
CyC2018 已提交
684 685 686 687
}
```

```java
C
CyC2018 已提交
688
public class ConcreteHandler2 extends Handler {
C
CyC2018 已提交
689

C
CyC2018 已提交
690 691 692
    public ConcreteHandler2(Handler successor) {
        super(successor);
    }
C
CyC2018 已提交
693

C
CyC2018 已提交
694

C
CyC2018 已提交
695 696 697 698 699 700 701 702 703 704
    @Override
    protected void handleRequest(Request request) {
        if (request.getType() == RequestType.TYPE2) {
            System.out.println(request.getName() + " is handle by ConcreteHandler2");
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
C
CyC2018 已提交
705 706 707 708
}
```

```java
C
CyC2018 已提交
709
public class Request {
C
CyC2018 已提交
710

C
CyC2018 已提交
711 712
    private RequestType type;
    private String name;
C
CyC2018 已提交
713

C
CyC2018 已提交
714

C
CyC2018 已提交
715 716 717 718
    public Request(RequestType type, String name) {
        this.type = type;
        this.name = name;
    }
C
CyC2018 已提交
719

C
CyC2018 已提交
720

C
CyC2018 已提交
721 722 723
    public RequestType getType() {
        return type;
    }
C
CyC2018 已提交
724

C
CyC2018 已提交
725

C
CyC2018 已提交
726 727 728
    public String getName() {
        return name;
    }
C
CyC2018 已提交
729
}
C
CyC2018 已提交
730

C
CyC2018 已提交
731 732 733
```

```java
C
CyC2018 已提交
734 735
public enum RequestType {
    TYPE1, TYPE2
C
CyC2018 已提交
736 737 738 739
}
```

```java
C
CyC2018 已提交
740
public class Client {
C
CyC2018 已提交
741

C
CyC2018 已提交
742
    public static void main(String[] args) {
C
CyC2018 已提交
743

C
CyC2018 已提交
744 745
        Handler handler1 = new ConcreteHandler1(null);
        Handler handler2 = new ConcreteHandler2(handler1);
C
CyC2018 已提交
746

C
CyC2018 已提交
747 748
        Request request1 = new Request(RequestType.TYPE1, "request1");
        handler2.handleRequest(request1);
C
CyC2018 已提交
749

C
CyC2018 已提交
750 751 752
        Request request2 = new Request(RequestType.TYPE2, "request2");
        handler2.handleRequest(request2);
    }
C
CyC2018 已提交
753 754 755 756
}
```

```html
C
CyC2018 已提交
757 758
request1 is handle by ConcreteHandler1
request2 is handle by ConcreteHandler2
C
CyC2018 已提交
759
```
C
CyC2018 已提交
760

C
CyC2018 已提交
761
### JDK
C
CyC2018 已提交
762

C
CyC2018 已提交
763 764 765
- [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29)
- [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html)
- [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-)
C
CyC2018 已提交
766

C
CyC2018 已提交
767
## 2. 命令(Command)
C
CyC2018 已提交
768

C
CyC2018 已提交
769
### Intent
C
CyC2018 已提交
770 771

将命令封装成对象中,具有以下作用:
C
CyC2018 已提交
772

C
CyC2018 已提交
773 774 775 776
- 使用命令来参数化其它对象
- 将命令放入队列中进行排队
- 将命令的操作记录到日志中
- 支持可撤销的操作
C
CyC2018 已提交
777

C
CyC2018 已提交
778
### Class Diagram
C
CyC2018 已提交
779

C
CyC2018 已提交
780 781 782 783
- Command:命令
- Receiver:命令接收者,也就是命令真正的执行者
- Invoker:通过它来调用命令
- Client:可以设置命令与命令的接收者
C
CyC2018 已提交
784

C
CyC2018 已提交
785
<div align="center"> <img src="pics/ae1b27b8-bc13-42e7-ac12-a2242e125499.png"/> </div><br>
C
CyC2018 已提交
786

C
CyC2018 已提交
787
### Implementation
C
CyC2018 已提交
788

C
CyC2018 已提交
789
设计一个遥控器,可以控制电灯开关。
C
CyC2018 已提交
790

C
CyC2018 已提交
791
<div align="center"> <img src="pics/e6bded8e-41a0-489a-88a6-638e88ab7666.jpg"/> </div><br>
C
CyC2018 已提交
792 793

```java
C
CyC2018 已提交
794 795
public interface Command {
    void execute();
C
CyC2018 已提交
796 797 798 799
}
```

```java
C
CyC2018 已提交
800 801
public class LightOnCommand implements Command {
    Light light;
C
CyC2018 已提交
802

C
CyC2018 已提交
803 804 805
    public LightOnCommand(Light light) {
        this.light = light;
    }
C
CyC2018 已提交
806

C
CyC2018 已提交
807 808 809 810
    @Override
    public void execute() {
        light.on();
    }
C
CyC2018 已提交
811 812 813 814
}
```

```java
C
CyC2018 已提交
815 816
public class LightOffCommand implements Command {
    Light light;
C
CyC2018 已提交
817

C
CyC2018 已提交
818 819 820
    public LightOffCommand(Light light) {
        this.light = light;
    }
C
CyC2018 已提交
821

C
CyC2018 已提交
822 823 824 825
    @Override
    public void execute() {
        light.off();
    }
C
CyC2018 已提交
826 827 828 829
}
```

```java
C
CyC2018 已提交
830
public class Light {
C
CyC2018 已提交
831

C
CyC2018 已提交
832 833 834
    public void on() {
        System.out.println("Light is on!");
    }
C
CyC2018 已提交
835

C
CyC2018 已提交
836 837 838
    public void off() {
        System.out.println("Light is off!");
    }
C
CyC2018 已提交
839 840 841 842 843
}
```

```java
/**
C
CyC2018 已提交
844 845 846 847 848 849
 * 遥控器
 */
public class Invoker {
    private Command[] onCommands;
    private Command[] offCommands;
    private final int slotNum = 7;
C
CyC2018 已提交
850

C
CyC2018 已提交
851 852 853 854
    public Invoker() {
        this.onCommands = new Command[slotNum];
        this.offCommands = new Command[slotNum];
    }
C
CyC2018 已提交
855

C
CyC2018 已提交
856 857 858
    public void setOnCommand(Command command, int slot) {
        onCommands[slot] = command;
    }
C
CyC2018 已提交
859

C
CyC2018 已提交
860 861 862
    public void setOffCommand(Command command, int slot) {
        offCommands[slot] = command;
    }
C
CyC2018 已提交
863

C
CyC2018 已提交
864 865 866
    public void onButtonWasPushed(int slot) {
        onCommands[slot].execute();
    }
C
CyC2018 已提交
867

C
CyC2018 已提交
868 869 870
    public void offButtonWasPushed(int slot) {
        offCommands[slot].execute();
    }
C
CyC2018 已提交
871 872 873 874
}
```

```java
C
CyC2018 已提交
875 876 877 878 879 880 881 882 883 884 885
public class Client {
    public static void main(String[] args) {
        Invoker invoker = new Invoker();
        Light light = new Light();
        Command lightOnCommand = new LightOnCommand(light);
        Command lightOffCommand = new LightOffCommand(light);
        invoker.setOnCommand(lightOnCommand, 0);
        invoker.setOffCommand(lightOffCommand, 0);
        invoker.onButtonWasPushed(0);
        invoker.offButtonWasPushed(0);
    }
C
CyC2018 已提交
886 887
}
```
C
CyC2018 已提交
888

C
CyC2018 已提交
889
### JDK
C
CyC2018 已提交
890

C
CyC2018 已提交
891 892 893
- [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
- [Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki)
- [javax.swing.Action](http://docs.oracle.com/javase/8/docs/api/javax/swing/Action.html)
C
CyC2018 已提交
894

C
CyC2018 已提交
895
## 3. 解释器(Interpreter)
C
CyC2018 已提交
896

C
CyC2018 已提交
897
### Intent
C
CyC2018 已提交
898 899 900

为语言创建解释器,通常由语言的语法和语法分析来定义。

C
CyC2018 已提交
901
### Class Diagram
C
CyC2018 已提交
902

C
CyC2018 已提交
903 904
- TerminalExpression:终结符表达式,每个终结符都需要一个 TerminalExpression。
- Context:上下文,包含解释器之外的一些全局信息。
C
CyC2018 已提交
905

C
CyC2018 已提交
906
<div align="center"> <img src="pics/794239e3-4baf-4aad-92df-f02f59b2a6fe.png"/> </div><br>
C
CyC2018 已提交
907

C
CyC2018 已提交
908
### Implementation
C
CyC2018 已提交
909

C
CyC2018 已提交
910
以下是一个规则检验器实现,具有 and 和 or 规则,通过规则可以构建一颗解析树,用来检验一个文本是否满足解析树定义的规则。
C
CyC2018 已提交
911

C
CyC2018 已提交
912
例如一颗解析树为 D And (A Or (B C)),文本 "D A" 满足该解析树定义的规则。
C
CyC2018 已提交
913

C
CyC2018 已提交
914
这里的 Context 指的是 String。
C
CyC2018 已提交
915 916

```java
C
CyC2018 已提交
917 918
public abstract class Expression {
    public abstract boolean interpret(String str);
C
CyC2018 已提交
919 920 921 922
}
```

```java
C
CyC2018 已提交
923
public class TerminalExpression extends Expression {
C
CyC2018 已提交
924

C
CyC2018 已提交
925
    private String literal = null;
C
CyC2018 已提交
926

C
CyC2018 已提交
927 928 929
    public TerminalExpression(String str) {
        literal = str;
    }
C
CyC2018 已提交
930

C
CyC2018 已提交
931 932 933 934 935 936 937 938 939 940
    public boolean interpret(String str) {
        StringTokenizer st = new StringTokenizer(str);
        while (st.hasMoreTokens()) {
            String test = st.nextToken();
            if (test.equals(literal)) {
                return true;
            }
        }
        return false;
    }
C
CyC2018 已提交
941 942 943 944
}
```

```java
C
CyC2018 已提交
945
public class AndExpression extends Expression {
C
CyC2018 已提交
946

C
CyC2018 已提交
947 948
    private Expression expression1 = null;
    private Expression expression2 = null;
C
CyC2018 已提交
949

C
CyC2018 已提交
950 951 952 953
    public AndExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }
C
CyC2018 已提交
954

C
CyC2018 已提交
955 956 957
    public boolean interpret(String str) {
        return expression1.interpret(str) && expression2.interpret(str);
    }
C
CyC2018 已提交
958 959 960 961
}
```

```java
C
CyC2018 已提交
962 963 964
public class OrExpression extends Expression {
    private Expression expression1 = null;
    private Expression expression2 = null;
C
CyC2018 已提交
965

C
CyC2018 已提交
966 967 968 969
    public OrExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }
C
CyC2018 已提交
970

C
CyC2018 已提交
971 972 973
    public boolean interpret(String str) {
        return expression1.interpret(str) || expression2.interpret(str);
    }
C
CyC2018 已提交
974 975 976 977
}
```

```java
C
CyC2018 已提交
978
public class Client {
C
CyC2018 已提交
979

C
CyC2018 已提交
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
    /**
     * 构建解析树
     */
    public static Expression buildInterpreterTree() {
        // Literal
        Expression terminal1 = new TerminalExpression("A");
        Expression terminal2 = new TerminalExpression("B");
        Expression terminal3 = new TerminalExpression("C");
        Expression terminal4 = new TerminalExpression("D");
        // B C
        Expression alternation1 = new OrExpression(terminal2, terminal3);
        // A Or (B C)
        Expression alternation2 = new OrExpression(terminal1, alternation1);
        // D And (A Or (B C))
        return new AndExpression(terminal4, alternation2);
    }
C
CyC2018 已提交
996

C
CyC2018 已提交
997 998 999 1000 1001 1002 1003
    public static void main(String[] args) {
        Expression define = buildInterpreterTree();
        String context1 = "D A";
        String context2 = "A B";
        System.out.println(define.interpret(context1));
        System.out.println(define.interpret(context2));
    }
C
CyC2018 已提交
1004 1005 1006 1007 1008 1009 1010 1011
}
```

```html
true
false
```

C
CyC2018 已提交
1012
### JDK
C
CyC2018 已提交
1013

C
CyC2018 已提交
1014 1015 1016 1017
- [java.util.Pattern](http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html)
- [java.text.Normalizer](http://docs.oracle.com/javase/8/docs/api/java/text/Normalizer.html)
- All subclasses of [java.text.Format](http://docs.oracle.com/javase/8/docs/api/java/text/Format.html)
- [javax.el.ELResolver](http://docs.oracle.com/javaee/7/api/javax/el/ELResolver.html)
C
CyC2018 已提交
1018

C
CyC2018 已提交
1019
## 4. 迭代器(Iterator)
C
CyC2018 已提交
1020

C
CyC2018 已提交
1021
### Intent
C
CyC2018 已提交
1022

C
CyC2018 已提交
1023 1024
提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。

C
CyC2018 已提交
1025
### Class Diagram
C
CyC2018 已提交
1026

C
CyC2018 已提交
1027 1028 1029
- Aggregate 是聚合类,其中 createIterator() 方法可以产生一个 Iterator;
- Iterator 主要定义了 hasNext() 和 next() 方法。
- Client 组合了 Aggregate,为了迭代遍历 Aggregate,也需要组合 Iterator。
C
CyC2018 已提交
1030

C
CyC2018 已提交
1031
<div align="center"> <img src="pics/b0f61ac2-a4b6-4042-9cf0-ccf4238c1ff7.png"/> </div><br>
C
CyC2018 已提交
1032

C
CyC2018 已提交
1033
### Implementation
C
CyC2018 已提交
1034 1035

```java
C
CyC2018 已提交
1036 1037
public interface Aggregate {
    Iterator createIterator();
C
CyC2018 已提交
1038 1039 1040 1041
}
```

```java
C
CyC2018 已提交
1042
public class ConcreteAggregate implements Aggregate {
C
CyC2018 已提交
1043

C
CyC2018 已提交
1044
    private Integer[] items;
C
CyC2018 已提交
1045

C
CyC2018 已提交
1046 1047 1048 1049 1050 1051
    public ConcreteAggregate() {
        items = new Integer[10];
        for (int i = 0; i < items.length; i++) {
            items[i] = i;
        }
    }
C
CyC2018 已提交
1052

C
CyC2018 已提交
1053 1054 1055 1056
    @Override
    public Iterator createIterator() {
        return new ConcreteIterator<Integer>(items);
    }
C
CyC2018 已提交
1057 1058 1059 1060
}
```

```java
C
CyC2018 已提交
1061
public interface Iterator<Item> {
C
CyC2018 已提交
1062

C
CyC2018 已提交
1063
    Item next();
C
CyC2018 已提交
1064

C
CyC2018 已提交
1065
    boolean hasNext();
C
CyC2018 已提交
1066 1067 1068 1069
}
```

```java
C
CyC2018 已提交
1070
public class ConcreteIterator<Item> implements Iterator {
C
CyC2018 已提交
1071

C
CyC2018 已提交
1072 1073
    private Item[] items;
    private int position = 0;
C
CyC2018 已提交
1074

C
CyC2018 已提交
1075 1076 1077
    public ConcreteIterator(Item[] items) {
        this.items = items;
    }
C
CyC2018 已提交
1078

C
CyC2018 已提交
1079 1080 1081 1082
    @Override
    public Object next() {
        return items[position++];
    }
C
CyC2018 已提交
1083

C
CyC2018 已提交
1084 1085 1086 1087
    @Override
    public boolean hasNext() {
        return position < items.length;
    }
C
CyC2018 已提交
1088 1089 1090 1091
}
```

```java
C
CyC2018 已提交
1092
public class Client {
C
CyC2018 已提交
1093

C
CyC2018 已提交
1094 1095 1096 1097 1098 1099 1100
    public static void main(String[] args) {
        Aggregate aggregate = new ConcreteAggregate();
        Iterator<Integer> iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
C
CyC2018 已提交
1101 1102
}
```
C
CyC2018 已提交
1103

C
CyC2018 已提交
1104
### JDK
C
CyC2018 已提交
1105

C
CyC2018 已提交
1106 1107
- [java.util.Iterator](http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html)
- [java.util.Enumeration](http://docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html)
C
CyC2018 已提交
1108

C
CyC2018 已提交
1109
## 5. 中介者(Mediator)
C
CyC2018 已提交
1110

C
CyC2018 已提交
1111
### Intent
C
CyC2018 已提交
1112

C
CyC2018 已提交
1113 1114
集中相关对象之间复杂的沟通和控制方式。

C
CyC2018 已提交
1115
### Class Diagram
C
CyC2018 已提交
1116

C
CyC2018 已提交
1117 1118
- Mediator:中介者,定义一个接口用于与各同事(Colleague)对象通信。
- Colleague:同事,相关对象
C
CyC2018 已提交
1119

C
CyC2018 已提交
1120
<div align="center"> <img src="pics/d0afdd23-c9a5-4d1c-9b3d-404bff3bd0d1.png"/> </div><br>
C
CyC2018 已提交
1121

C
CyC2018 已提交
1122
### Implementation
C
CyC2018 已提交
1123 1124 1125

Alarm(闹钟)、CoffeePot(咖啡壶)、Calendar(日历)、Sprinkler(喷头)是一组相关的对象,在某个对象的事件产生时需要去操作其它对象,形成了下面这种依赖结构:

C
CyC2018 已提交
1126
<div align="center"> <img src="pics/82cfda3b-b53b-4c89-9fdb-26dd2db0cd02.jpg"/> </div><br>
C
CyC2018 已提交
1127 1128 1129

使用中介者模式可以将复杂的依赖结构变成星形结构:

C
CyC2018 已提交
1130
<div align="center"> <img src="pics/5359cbf5-5a79-4874-9b17-f23c53c2cb80.jpg"/> </div><br>
C
CyC2018 已提交
1131 1132

```java
C
CyC2018 已提交
1133 1134
public abstract class Colleague {
    public abstract void onEvent(Mediator mediator);
C
CyC2018 已提交
1135 1136 1137 1138
}
```

```java
C
CyC2018 已提交
1139
public class Alarm extends Colleague {
C
CyC2018 已提交
1140

C
CyC2018 已提交
1141 1142 1143 1144
    @Override
    public void onEvent(Mediator mediator) {
        mediator.doEvent("alarm");
    }
C
CyC2018 已提交
1145

C
CyC2018 已提交
1146 1147 1148
    public void doAlarm() {
        System.out.println("doAlarm()");
    }
C
CyC2018 已提交
1149 1150 1151 1152
}
```

```java
C
CyC2018 已提交
1153 1154 1155 1156 1157
public class CoffeePot extends Colleague {
    @Override
    public void onEvent(Mediator mediator) {
        mediator.doEvent("coffeePot");
    }
C
CyC2018 已提交
1158

C
CyC2018 已提交
1159 1160 1161
    public void doCoffeePot() {
        System.out.println("doCoffeePot()");
    }
C
CyC2018 已提交
1162 1163 1164 1165
}
```

```java
C
CyC2018 已提交
1166 1167 1168 1169 1170
public class Calender extends Colleague {
    @Override
    public void onEvent(Mediator mediator) {
        mediator.doEvent("calender");
    }
C
CyC2018 已提交
1171

C
CyC2018 已提交
1172 1173 1174
    public void doCalender() {
        System.out.println("doCalender()");
    }
C
CyC2018 已提交
1175 1176 1177 1178
}
```

```java
C
CyC2018 已提交
1179 1180 1181 1182 1183
public class Sprinkler extends Colleague {
    @Override
    public void onEvent(Mediator mediator) {
        mediator.doEvent("sprinkler");
    }
C
CyC2018 已提交
1184

C
CyC2018 已提交
1185 1186 1187
    public void doSprinkler() {
        System.out.println("doSprinkler()");
    }
C
CyC2018 已提交
1188 1189 1190 1191
}
```

```java
C
CyC2018 已提交
1192 1193
public abstract class Mediator {
    public abstract void doEvent(String eventType);
C
CyC2018 已提交
1194 1195 1196 1197
}
```

```java
C
CyC2018 已提交
1198 1199 1200 1201 1202
public class ConcreteMediator extends Mediator {
    private Alarm alarm;
    private CoffeePot coffeePot;
    private Calender calender;
    private Sprinkler sprinkler;
C
CyC2018 已提交
1203

C
CyC2018 已提交
1204 1205 1206 1207 1208 1209
    public ConcreteMediator(Alarm alarm, CoffeePot coffeePot, Calender calender, Sprinkler sprinkler) {
        this.alarm = alarm;
        this.coffeePot = coffeePot;
        this.calender = calender;
        this.sprinkler = sprinkler;
    }
C
CyC2018 已提交
1210

C
CyC2018 已提交
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
    @Override
    public void doEvent(String eventType) {
        switch (eventType) {
            case "alarm":
                doAlarmEvent();
                break;
            case "coffeePot":
                doCoffeePotEvent();
                break;
            case "calender":
                doCalenderEvent();
                break;
            default:
                doSprinklerEvent();
        }
    }
C
CyC2018 已提交
1227

C
CyC2018 已提交
1228 1229 1230 1231 1232 1233
    public void doAlarmEvent() {
        alarm.doAlarm();
        coffeePot.doCoffeePot();
        calender.doCalender();
        sprinkler.doSprinkler();
    }
C
CyC2018 已提交
1234

C
CyC2018 已提交
1235 1236 1237
    public void doCoffeePotEvent() {
        // ...
    }
C
CyC2018 已提交
1238

C
CyC2018 已提交
1239 1240 1241
    public void doCalenderEvent() {
        // ...
    }
C
CyC2018 已提交
1242

C
CyC2018 已提交
1243 1244 1245
    public void doSprinklerEvent() {
        // ...
    }
C
CyC2018 已提交
1246 1247 1248 1249
}
```

```java
C
CyC2018 已提交
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259
public class Client {
    public static void main(String[] args) {
        Alarm alarm = new Alarm();
        CoffeePot coffeePot = new CoffeePot();
        Calender calender = new Calender();
        Sprinkler sprinkler = new Sprinkler();
        Mediator mediator = new ConcreteMediator(alarm, coffeePot, calender, sprinkler);
        // 闹钟事件到达,调用中介者就可以操作相关对象
        alarm.onEvent(mediator);
    }
C
CyC2018 已提交
1260 1261 1262 1263 1264 1265 1266 1267 1268
}
```

```java
doAlarm()
doCoffeePot()
doCalender()
doSprinkler()
```
C
CyC2018 已提交
1269

C
CyC2018 已提交
1270
### JDK
C
CyC2018 已提交
1271

C
CyC2018 已提交
1272 1273 1274 1275 1276
- All scheduleXXX() methods of [java.util.Timer](http://docs.oracle.com/javase/8/docs/api/java/util/Timer.html)
- [java.util.concurrent.Executor#execute()](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable-)
- submit() and invokeXXX() methods of [java.util.concurrent.ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
- scheduleXXX() methods of [java.util.concurrent.ScheduledExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html)
- [java.lang.reflect.Method#invoke()](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#invoke-java.lang.Object-java.lang.Object...-)
C
CyC2018 已提交
1277

C
CyC2018 已提交
1278
## 6. 备忘录(Memento)
C
CyC2018 已提交
1279

C
CyC2018 已提交
1280
### Intent
C
CyC2018 已提交
1281 1282 1283

在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。

C
CyC2018 已提交
1284
### Class Diagram
C
CyC2018 已提交
1285

C
CyC2018 已提交
1286 1287 1288
- Originator:原始对象
- Caretaker:负责保存好备忘录
- Menento:备忘录,存储原始对象的的状态。备忘录实际上有两个接口,一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。
C
CyC2018 已提交
1289

C
CyC2018 已提交
1290
<div align="center"> <img src="pics/867e93eb-3161-4f39-b2d2-c0cd3788e194.png"/> </div><br>
C
CyC2018 已提交
1291

C
CyC2018 已提交
1292
### Implementation
C
CyC2018 已提交
1293 1294 1295

以下实现了一个简单计算器程序,可以输入两个值,然后计算这两个值的和。备忘录模式允许将这两个值存储起来,然后在某个时刻用存储的状态进行恢复。

C
CyC2018 已提交
1296
实现参考:[Memento Pattern - Calculator Example - Java Sourcecode](https://www.oodesign.com/memento-pattern-calculator-example-java-sourcecode.html)
C
CyC2018 已提交
1297 1298 1299

```java
/**
C
CyC2018 已提交
1300 1301 1302
 * Originator Interface
 */
public interface Calculator {
C
CyC2018 已提交
1303

C
CyC2018 已提交
1304 1305
    // Create Memento
    PreviousCalculationToCareTaker backupLastCalculation();
C
CyC2018 已提交
1306

C
CyC2018 已提交
1307 1308
    // setMemento
    void restorePreviousCalculation(PreviousCalculationToCareTaker memento);
C
CyC2018 已提交
1309

C
CyC2018 已提交
1310
    int getCalculationResult();
C
CyC2018 已提交
1311

C
CyC2018 已提交
1312
    void setFirstNumber(int firstNumber);
C
CyC2018 已提交
1313

C
CyC2018 已提交
1314
    void setSecondNumber(int secondNumber);
C
CyC2018 已提交
1315 1316 1317 1318 1319
}
```

```java
/**
C
CyC2018 已提交
1320 1321 1322
 * Originator Implementation
 */
public class CalculatorImp implements Calculator {
C
CyC2018 已提交
1323

C
CyC2018 已提交
1324 1325
    private int firstNumber;
    private int secondNumber;
C
CyC2018 已提交
1326

C
CyC2018 已提交
1327 1328 1329 1330 1331
    @Override
    public PreviousCalculationToCareTaker backupLastCalculation() {
        // create a memento object used for restoring two numbers
        return new PreviousCalculationImp(firstNumber, secondNumber);
    }
C
CyC2018 已提交
1332

C
CyC2018 已提交
1333 1334 1335 1336 1337
    @Override
    public void restorePreviousCalculation(PreviousCalculationToCareTaker memento) {
        this.firstNumber = ((PreviousCalculationToOriginator) memento).getFirstNumber();
        this.secondNumber = ((PreviousCalculationToOriginator) memento).getSecondNumber();
    }
C
CyC2018 已提交
1338

C
CyC2018 已提交
1339 1340 1341 1342 1343
    @Override
    public int getCalculationResult() {
        // result is adding two numbers
        return firstNumber + secondNumber;
    }
C
CyC2018 已提交
1344

C
CyC2018 已提交
1345 1346 1347 1348
    @Override
    public void setFirstNumber(int firstNumber) {
        this.firstNumber = firstNumber;
    }
C
CyC2018 已提交
1349

C
CyC2018 已提交
1350 1351 1352 1353
    @Override
    public void setSecondNumber(int secondNumber) {
        this.secondNumber = secondNumber;
    }
C
CyC2018 已提交
1354 1355 1356 1357 1358
}
```

```java
/**
C
CyC2018 已提交
1359 1360 1361 1362 1363 1364 1365
 * Memento Interface to Originator
 *
 * This interface allows the originator to restore its state
 */
public interface PreviousCalculationToOriginator {
    int getFirstNumber();
    int getSecondNumber();
C
CyC2018 已提交
1366 1367 1368 1369 1370
}
```

```java
/**
C
CyC2018 已提交
1371 1372 1373 1374
 *  Memento interface to CalculatorOperator (Caretaker)
 */
public interface PreviousCalculationToCareTaker {
    // no operations permitted for the caretaker
C
CyC2018 已提交
1375 1376 1377 1378 1379
}
```

```java
/**
C
CyC2018 已提交
1380 1381 1382 1383 1384 1385
 * Memento Object Implementation
 * <p>
 * Note that this object implements both interfaces to Originator and CareTaker
 */
public class PreviousCalculationImp implements PreviousCalculationToCareTaker,
        PreviousCalculationToOriginator {
C
CyC2018 已提交
1386

C
CyC2018 已提交
1387 1388
    private int firstNumber;
    private int secondNumber;
C
CyC2018 已提交
1389

C
CyC2018 已提交
1390 1391 1392 1393
    public PreviousCalculationImp(int firstNumber, int secondNumber) {
        this.firstNumber = firstNumber;
        this.secondNumber = secondNumber;
    }
C
CyC2018 已提交
1394

C
CyC2018 已提交
1395 1396 1397 1398
    @Override
    public int getFirstNumber() {
        return firstNumber;
    }
C
CyC2018 已提交
1399

C
CyC2018 已提交
1400 1401 1402 1403
    @Override
    public int getSecondNumber() {
        return secondNumber;
    }
C
CyC2018 已提交
1404 1405 1406 1407 1408
}
```

```java
/**
C
CyC2018 已提交
1409 1410 1411
 * CareTaker object
 */
public class Client {
C
CyC2018 已提交
1412

C
CyC2018 已提交
1413 1414 1415
    public static void main(String[] args) {
        // program starts
        Calculator calculator = new CalculatorImp();
C
CyC2018 已提交
1416

C
CyC2018 已提交
1417 1418 1419
        // assume user enters two numbers
        calculator.setFirstNumber(10);
        calculator.setSecondNumber(100);
C
CyC2018 已提交
1420

C
CyC2018 已提交
1421 1422
        // find result
        System.out.println(calculator.getCalculationResult());
C
CyC2018 已提交
1423

C
CyC2018 已提交
1424 1425
        // Store result of this calculation in case of error
        PreviousCalculationToCareTaker memento = calculator.backupLastCalculation();
C
CyC2018 已提交
1426

C
CyC2018 已提交
1427 1428
        // user enters a number
        calculator.setFirstNumber(17);
C
CyC2018 已提交
1429

C
CyC2018 已提交
1430 1431
        // user enters a wrong second number and calculates result
        calculator.setSecondNumber(-290);
C
CyC2018 已提交
1432

C
CyC2018 已提交
1433 1434
        // calculate result
        System.out.println(calculator.getCalculationResult());
C
CyC2018 已提交
1435

C
CyC2018 已提交
1436 1437
        // user hits CTRL + Z to undo last operation and see last result
        calculator.restorePreviousCalculation(memento);
C
CyC2018 已提交
1438

C
CyC2018 已提交
1439 1440 1441
        // result restored
        System.out.println(calculator.getCalculationResult());
    }
C
CyC2018 已提交
1442 1443 1444 1445 1446 1447 1448 1449 1450
}
```

```html
110
-273
110
```

C
CyC2018 已提交
1451
### JDK
C
CyC2018 已提交
1452

C
CyC2018 已提交
1453
- java.io.Serializable
C
CyC2018 已提交
1454

C
CyC2018 已提交
1455
## 7. 观察者(Observer)
C
CyC2018 已提交
1456

C
CyC2018 已提交
1457
### Intent
C
CyC2018 已提交
1458 1459 1460

定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。

C
CyC2018 已提交
1461 1462
主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。

C
CyC2018 已提交
1463
<div align="center"> <img src="pics/7a3c6a30-c735-4edb-8115-337288a4f0f2.jpg" width="600"/> </div><br>
C
CyC2018 已提交
1464

C
CyC2018 已提交
1465
### Class Diagram
C
CyC2018 已提交
1466

C
CyC2018 已提交
1467
主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。
C
CyC2018 已提交
1468

C
CyC2018 已提交
1469
观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。
C
CyC2018 已提交
1470

C
CyC2018 已提交
1471
<div align="center"> <img src="pics/0df5d84c-e7ca-4e3a-a688-bb8e68894467.png"/> </div><br>
C
CyC2018 已提交
1472

C
CyC2018 已提交
1473
### Implementation
C
CyC2018 已提交
1474 1475 1476

天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。

C
CyC2018 已提交
1477
<div align="center"> <img src="pics/b1df9732-86ce-4d69-9f06-fba1db7b3b5a.jpg"/> </div><br>
C
CyC2018 已提交
1478 1479

```java
C
CyC2018 已提交
1480 1481
public interface Subject {
    void registerObserver(Observer o);
C
CyC2018 已提交
1482

C
CyC2018 已提交
1483
    void removeObserver(Observer o);
C
CyC2018 已提交
1484

C
CyC2018 已提交
1485
    void notifyObserver();
C
CyC2018 已提交
1486 1487 1488 1489
}
```

```java
C
CyC2018 已提交
1490 1491 1492 1493 1494
public class WeatherData implements Subject {
    private List<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;
C
CyC2018 已提交
1495

C
CyC2018 已提交
1496 1497 1498
    public WeatherData() {
        observers = new ArrayList<>();
    }
C
CyC2018 已提交
1499

C
CyC2018 已提交
1500 1501 1502 1503 1504 1505
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObserver();
    }
C
CyC2018 已提交
1506

C
CyC2018 已提交
1507 1508 1509 1510
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }
C
CyC2018 已提交
1511

C
CyC2018 已提交
1512 1513 1514 1515 1516 1517 1518
    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }
C
CyC2018 已提交
1519

C
CyC2018 已提交
1520 1521 1522 1523 1524 1525
    @Override
    public void notifyObserver() {
        for (Observer o : observers) {
            o.update(temperature, humidity, pressure);
        }
    }
C
CyC2018 已提交
1526 1527 1528 1529
}
```

```java
C
CyC2018 已提交
1530 1531
public interface Observer {
    void update(float temp, float humidity, float pressure);
C
CyC2018 已提交
1532 1533 1534 1535
}
```

```java
C
CyC2018 已提交
1536
public class StatisticsDisplay implements Observer {
C
CyC2018 已提交
1537

C
CyC2018 已提交
1538 1539 1540
    public StatisticsDisplay(Subject weatherData) {
        weatherData.reisterObserver(this);
    }
C
CyC2018 已提交
1541

C
CyC2018 已提交
1542 1543 1544 1545
    @Override
    public void update(float temp, float humidity, float pressure) {
        System.out.println("StatisticsDisplay.update: " + temp + " " + humidity + " " + pressure);
    }
C
CyC2018 已提交
1546 1547 1548 1549
}
```

```java
C
CyC2018 已提交
1550
public class CurrentConditionsDisplay implements Observer {
C
CyC2018 已提交
1551

C
CyC2018 已提交
1552 1553 1554
    public CurrentConditionsDisplay(Subject weatherData) {
        weatherData.registerObserver(this);
    }
C
CyC2018 已提交
1555

C
CyC2018 已提交
1556 1557 1558 1559
    @Override
    public void update(float temp, float humidity, float pressure) {
        System.out.println("CurrentConditionsDisplay.update: " + temp + " " + humidity + " " + pressure);
    }
C
CyC2018 已提交
1560 1561 1562 1563
}
```

```java
C
CyC2018 已提交
1564 1565 1566 1567 1568
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
C
CyC2018 已提交
1569

C
CyC2018 已提交
1570 1571 1572
        weatherData.setMeasurements(0, 0, 0);
        weatherData.setMeasurements(1, 1, 1);
    }
C
CyC2018 已提交
1573 1574 1575 1576
}
```

```html
C
CyC2018 已提交
1577 1578 1579 1580
CurrentConditionsDisplay.update: 0.0 0.0 0.0
StatisticsDisplay.update: 0.0 0.0 0.0
CurrentConditionsDisplay.update: 1.0 1.0 1.0
StatisticsDisplay.update: 1.0 1.0 1.0
C
CyC2018 已提交
1581 1582
```

C
CyC2018 已提交
1583
### JDK
C
CyC2018 已提交
1584

C
CyC2018 已提交
1585 1586 1587 1588
- [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html)
- [java.util.EventListener](http://docs.oracle.com/javase/8/docs/api/java/util/EventListener.html)
- [javax.servlet.http.HttpSessionBindingListener](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionBindingListener.html)
- [RxJava](https://github.com/ReactiveX/RxJava)
C
CyC2018 已提交
1589

C
CyC2018 已提交
1590
## 8. 状态(State)
C
CyC2018 已提交
1591

C
CyC2018 已提交
1592
### Intent
C
CyC2018 已提交
1593 1594 1595

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。

C
CyC2018 已提交
1596
### Class Diagram
C
CyC2018 已提交
1597

C
CyC2018 已提交
1598
<div align="center"> <img src="pics/c5085437-54df-4304-b62d-44b961711ba7.png"/> </div><br>
C
CyC2018 已提交
1599

C
CyC2018 已提交
1600
### Implementation
C
CyC2018 已提交
1601 1602 1603

糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。

C
CyC2018 已提交
1604
<div align="center"> <img src="pics/396be981-3f2c-4fd9-8101-dbf9c841504b.jpg" width="600"/> </div><br>
C
CyC2018 已提交
1605 1606

```java
C
CyC2018 已提交
1607 1608 1609 1610 1611
public interface State {
    /**
     * 投入 25 分钱
     */
    void insertQuarter();
C
CyC2018 已提交
1612

C
CyC2018 已提交
1613 1614 1615 1616
    /**
     * 退回 25 分钱
     */
    void ejectQuarter();
C
CyC2018 已提交
1617

C
CyC2018 已提交
1618 1619 1620 1621
    /**
     * 转动曲柄
     */
    void turnCrank();
C
CyC2018 已提交
1622

C
CyC2018 已提交
1623 1624 1625 1626
    /**
     * 发放糖果
     */
    void dispense();
C
CyC2018 已提交
1627 1628 1629 1630
}
```

```java
C
CyC2018 已提交
1631
public class HasQuarterState implements State {
C
CyC2018 已提交
1632

C
CyC2018 已提交
1633
    private GumballMachine gumballMachine;
C
CyC2018 已提交
1634

C
CyC2018 已提交
1635 1636 1637
    public HasQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
C
CyC2018 已提交
1638

C
CyC2018 已提交
1639 1640 1641 1642
    @Override
    public void insertQuarter() {
        System.out.println("You can't insert another quarter");
    }
C
CyC2018 已提交
1643

C
CyC2018 已提交
1644 1645 1646 1647 1648
    @Override
    public void ejectQuarter() {
        System.out.println("Quarter returned");
        gumballMachine.setState(gumballMachine.getNoQuarterState());
    }
C
CyC2018 已提交
1649

C
CyC2018 已提交
1650 1651 1652 1653 1654
    @Override
    public void turnCrank() {
        System.out.println("You turned...");
        gumballMachine.setState(gumballMachine.getSoldState());
    }
C
CyC2018 已提交
1655

C
CyC2018 已提交
1656 1657 1658 1659
    @Override
    public void dispense() {
        System.out.println("No gumball dispensed");
    }
C
CyC2018 已提交
1660 1661 1662 1663
}
```

```java
C
CyC2018 已提交
1664
public class NoQuarterState implements State {
C
CyC2018 已提交
1665

C
CyC2018 已提交
1666
    GumballMachine gumballMachine;
C
CyC2018 已提交
1667

C
CyC2018 已提交
1668 1669 1670
    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
C
CyC2018 已提交
1671

C
CyC2018 已提交
1672 1673 1674 1675 1676
    @Override
    public void insertQuarter() {
        System.out.println("You insert a quarter");
        gumballMachine.setState(gumballMachine.getHasQuarterState());
    }
C
CyC2018 已提交
1677

C
CyC2018 已提交
1678 1679 1680 1681
    @Override
    public void ejectQuarter() {
        System.out.println("You haven't insert a quarter");
    }
C
CyC2018 已提交
1682

C
CyC2018 已提交
1683 1684 1685 1686
    @Override
    public void turnCrank() {
        System.out.println("You turned, but there's no quarter");
    }
C
CyC2018 已提交
1687

C
CyC2018 已提交
1688 1689 1690 1691
    @Override
    public void dispense() {
        System.out.println("You need to pay first");
    }
C
CyC2018 已提交
1692 1693 1694 1695
}
```

```java
C
CyC2018 已提交
1696
public class SoldOutState implements State {
C
CyC2018 已提交
1697

C
CyC2018 已提交
1698
    GumballMachine gumballMachine;
C
CyC2018 已提交
1699

C
CyC2018 已提交
1700 1701 1702
    public SoldOutState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
C
CyC2018 已提交
1703

C
CyC2018 已提交
1704 1705 1706 1707
    @Override
    public void insertQuarter() {
        System.out.println("You can't insert a quarter, the machine is sold out");
    }
C
CyC2018 已提交
1708

C
CyC2018 已提交
1709 1710 1711 1712
    @Override
    public void ejectQuarter() {
        System.out.println("You can't eject, you haven't inserted a quarter yet");
    }
C
CyC2018 已提交
1713

C
CyC2018 已提交
1714 1715 1716 1717
    @Override
    public void turnCrank() {
        System.out.println("You turned, but there are no gumballs");
    }
C
CyC2018 已提交
1718

C
CyC2018 已提交
1719 1720 1721 1722
    @Override
    public void dispense() {
        System.out.println("No gumball dispensed");
    }
C
CyC2018 已提交
1723 1724 1725 1726
}
```

```java
C
CyC2018 已提交
1727
public class SoldState implements State {
C
CyC2018 已提交
1728

C
CyC2018 已提交
1729
    GumballMachine gumballMachine;
C
CyC2018 已提交
1730

C
CyC2018 已提交
1731 1732 1733
    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
C
CyC2018 已提交
1734

C
CyC2018 已提交
1735 1736 1737 1738
    @Override
    public void insertQuarter() {
        System.out.println("Please wait, we're already giving you a gumball");
    }
C
CyC2018 已提交
1739

C
CyC2018 已提交
1740 1741 1742 1743
    @Override
    public void ejectQuarter() {
        System.out.println("Sorry, you already turned the crank");
    }
C
CyC2018 已提交
1744

C
CyC2018 已提交
1745 1746 1747 1748
    @Override
    public void turnCrank() {
        System.out.println("Turning twice doesn't get you another gumball!");
    }
C
CyC2018 已提交
1749

C
CyC2018 已提交
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759
    @Override
    public void dispense() {
        gumballMachine.releaseBall();
        if (gumballMachine.getCount() > 0) {
            gumballMachine.setState(gumballMachine.getNoQuarterState());
        } else {
            System.out.println("Oops, out of gumballs");
            gumballMachine.setState(gumballMachine.getSoldOutState());
        }
    }
C
CyC2018 已提交
1760 1761 1762 1763
}
```

```java
C
CyC2018 已提交
1764
public class GumballMachine {
C
CyC2018 已提交
1765

C
CyC2018 已提交
1766 1767 1768 1769
    private State soldOutState;
    private State noQuarterState;
    private State hasQuarterState;
    private State soldState;
C
CyC2018 已提交
1770

C
CyC2018 已提交
1771 1772
    private State state;
    private int count = 0;
C
CyC2018 已提交
1773

C
CyC2018 已提交
1774 1775 1776 1777 1778 1779
    public GumballMachine(int numberGumballs) {
        count = numberGumballs;
        soldOutState = new SoldOutState(this);
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldState = new SoldState(this);
C
CyC2018 已提交
1780

C
CyC2018 已提交
1781 1782 1783 1784 1785 1786
        if (numberGumballs > 0) {
            state = noQuarterState;
        } else {
            state = soldOutState;
        }
    }
C
CyC2018 已提交
1787

C
CyC2018 已提交
1788 1789 1790
    public void insertQuarter() {
        state.insertQuarter();
    }
C
CyC2018 已提交
1791

C
CyC2018 已提交
1792 1793 1794
    public void ejectQuarter() {
        state.ejectQuarter();
    }
C
CyC2018 已提交
1795

C
CyC2018 已提交
1796 1797 1798 1799
    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }
C
CyC2018 已提交
1800

C
CyC2018 已提交
1801 1802 1803
    public void setState(State state) {
        this.state = state;
    }
C
CyC2018 已提交
1804

C
CyC2018 已提交
1805 1806 1807 1808 1809 1810
    public void releaseBall() {
        System.out.println("A gumball comes rolling out the slot...");
        if (count != 0) {
            count -= 1;
        }
    }
C
CyC2018 已提交
1811

C
CyC2018 已提交
1812 1813 1814
    public State getSoldOutState() {
        return soldOutState;
    }
C
CyC2018 已提交
1815

C
CyC2018 已提交
1816 1817 1818
    public State getNoQuarterState() {
        return noQuarterState;
    }
C
CyC2018 已提交
1819

C
CyC2018 已提交
1820 1821 1822
    public State getHasQuarterState() {
        return hasQuarterState;
    }
C
CyC2018 已提交
1823

C
CyC2018 已提交
1824 1825 1826
    public State getSoldState() {
        return soldState;
    }
C
CyC2018 已提交
1827

C
CyC2018 已提交
1828 1829 1830
    public int getCount() {
        return count;
    }
C
CyC2018 已提交
1831 1832 1833 1834
}
```

```java
C
CyC2018 已提交
1835
public class Client {
C
CyC2018 已提交
1836

C
CyC2018 已提交
1837 1838
    public static void main(String[] args) {
        GumballMachine gumballMachine = new GumballMachine(5);
C
CyC2018 已提交
1839

C
CyC2018 已提交
1840 1841
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
C
CyC2018 已提交
1842

C
CyC2018 已提交
1843 1844 1845
        gumballMachine.insertQuarter();
        gumballMachine.ejectQuarter();
        gumballMachine.turnCrank();
C
CyC2018 已提交
1846

C
CyC2018 已提交
1847 1848 1849 1850 1851
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        gumballMachine.ejectQuarter();
C
CyC2018 已提交
1852

C
CyC2018 已提交
1853 1854 1855 1856 1857 1858 1859 1860
        gumballMachine.insertQuarter();
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
    }
C
CyC2018 已提交
1861 1862 1863 1864
}
```

```html
C
CyC2018 已提交
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894
You insert a quarter
You turned...
A gumball comes rolling out the slot...
You insert a quarter
Quarter returned
You turned, but there's no quarter
You need to pay first
You insert a quarter
You turned...
A gumball comes rolling out the slot...
You insert a quarter
You turned...
A gumball comes rolling out the slot...
You haven't insert a quarter
You insert a quarter
You can't insert another quarter
You turned...
A gumball comes rolling out the slot...
You insert a quarter
You turned...
A gumball comes rolling out the slot...
Oops, out of gumballs
You can't insert a quarter, the machine is sold out
You turned, but there are no gumballs
No gumball dispensed
```

## 9. 策略(Strategy)

### Intent
C
CyC2018 已提交
1895

C
CyC2018 已提交
1896 1897 1898 1899
定义一系列算法,封装每个算法,并使它们可以互换。

策略模式可以让算法独立于使用它的客户端。

C
CyC2018 已提交
1900
### Class Diagram
C
CyC2018 已提交
1901

C
CyC2018 已提交
1902 1903
- Strategy 接口定义了一个算法族,它们都实现了  behavior() 方法。
- Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。
C
CyC2018 已提交
1904

C
CyC2018 已提交
1905
<div align="center"> <img src="pics/1fc969e4-0e7c-441b-b53c-01950d2f2be5.png"/> </div><br>
C
CyC2018 已提交
1906

C
CyC2018 已提交
1907
### 与状态模式的比较
C
CyC2018 已提交
1908

C
CyC2018 已提交
1909
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。
C
CyC2018 已提交
1910

C
CyC2018 已提交
1911
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。
C
CyC2018 已提交
1912

C
CyC2018 已提交
1913
### Implementation
C
CyC2018 已提交
1914 1915 1916 1917

设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为。

```java
C
CyC2018 已提交
1918 1919
public interface QuackBehavior {
    void quack();
C
CyC2018 已提交
1920 1921 1922 1923
}
```

```java
C
CyC2018 已提交
1924 1925 1926 1927 1928
public class Quack implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("quack!");
    }
C
CyC2018 已提交
1929 1930 1931 1932
}
```

```java
C
CyC2018 已提交
1933 1934 1935 1936 1937
public class Squeak implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("squeak!");
    }
C
CyC2018 已提交
1938 1939 1940 1941
}
```

```java
C
CyC2018 已提交
1942
public class Duck {
C
CyC2018 已提交
1943

C
CyC2018 已提交
1944
    private QuackBehavior quackBehavior;
C
CyC2018 已提交
1945

C
CyC2018 已提交
1946 1947 1948 1949 1950
    public void performQuack() {
        if (quackBehavior != null) {
            quackBehavior.quack();
        }
    }
C
CyC2018 已提交
1951

C
CyC2018 已提交
1952 1953 1954
    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }
C
CyC2018 已提交
1955 1956 1957 1958
}
```

```java
C
CyC2018 已提交
1959
public class Client {
C
CyC2018 已提交
1960

C
CyC2018 已提交
1961 1962 1963 1964 1965 1966 1967
    public static void main(String[] args) {
        Duck duck = new Duck();
        duck.setQuackBehavior(new Squeak());
        duck.performQuack();
        duck.setQuackBehavior(new Quack());
        duck.performQuack();
    }
C
CyC2018 已提交
1968 1969 1970 1971 1972 1973 1974
}
```

```html
squeak!
quack!
```
C
CyC2018 已提交
1975

C
CyC2018 已提交
1976
### JDK
C
CyC2018 已提交
1977

C
CyC2018 已提交
1978 1979 1980
- java.util.Comparator#compare()
- javax.servlet.http.HttpServlet
- javax.servlet.Filter#doFilter()
C
CyC2018 已提交
1981

C
CyC2018 已提交
1982
## 10. 模板方法(Template Method)
C
CyC2018 已提交
1983

C
CyC2018 已提交
1984
### Intent
C
CyC2018 已提交
1985

C
CyC2018 已提交
1986 1987 1988 1989
定义算法框架,并将一些步骤的实现延迟到子类。

通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

C
CyC2018 已提交
1990
### Class Diagram
C
CyC2018 已提交
1991

C
CyC2018 已提交
1992
<div align="center"> <img src="pics/c3c1c0e8-3a78-4426-961f-b46dd0879dd8.png"/> </div><br>
C
CyC2018 已提交
1993

C
CyC2018 已提交
1994
### Implementation
C
CyC2018 已提交
1995 1996 1997

冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。

C
CyC2018 已提交
1998
<div align="center"> <img src="pics/11236498-1417-46ce-a1b0-e10054256955.png"/> </div><br>
C
CyC2018 已提交
1999 2000

```java
C
CyC2018 已提交
2001
public abstract class CaffeineBeverage {
C
CyC2018 已提交
2002

C
CyC2018 已提交
2003 2004 2005 2006 2007 2008
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }
C
CyC2018 已提交
2009

C
CyC2018 已提交
2010
    abstract void brew();
C
CyC2018 已提交
2011

C
CyC2018 已提交
2012
    abstract void addCondiments();
C
CyC2018 已提交
2013

C
CyC2018 已提交
2014 2015 2016
    void boilWater() {
        System.out.println("boilWater");
    }
C
CyC2018 已提交
2017

C
CyC2018 已提交
2018 2019 2020
    void pourInCup() {
        System.out.println("pourInCup");
    }
C
CyC2018 已提交
2021 2022 2023 2024
}
```

```java
C
CyC2018 已提交
2025 2026 2027 2028 2029
public class Coffee extends CaffeineBeverage {
    @Override
    void brew() {
        System.out.println("Coffee.brew");
    }
C
CyC2018 已提交
2030

C
CyC2018 已提交
2031 2032 2033 2034
    @Override
    void addCondiments() {
        System.out.println("Coffee.addCondiments");
    }
C
CyC2018 已提交
2035 2036 2037 2038
}
```

```java
C
CyC2018 已提交
2039 2040 2041 2042 2043
public class Tea extends CaffeineBeverage {
    @Override
    void brew() {
        System.out.println("Tea.brew");
    }
C
CyC2018 已提交
2044

C
CyC2018 已提交
2045 2046 2047 2048
    @Override
    void addCondiments() {
        System.out.println("Tea.addCondiments");
    }
C
CyC2018 已提交
2049 2050 2051 2052
}
```

```java
C
CyC2018 已提交
2053 2054 2055 2056 2057 2058 2059 2060
public class Client {
    public static void main(String[] args) {
        CaffeineBeverage caffeineBeverage = new Coffee();
        caffeineBeverage.prepareRecipe();
        System.out.println("-----------");
        caffeineBeverage = new Tea();
        caffeineBeverage.prepareRecipe();
    }
C
CyC2018 已提交
2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
}
```

```html
boilWater
Coffee.brew
pourInCup
Coffee.addCondiments
-----------
boilWater
Tea.brew
pourInCup
Tea.addCondiments
```
C
CyC2018 已提交
2075

C
CyC2018 已提交
2076
### JDK
C
CyC2018 已提交
2077

C
CyC2018 已提交
2078 2079 2080 2081
- java.util.Collections#sort()
- java.io.InputStream#skip()
- java.io.InputStream#read()
- java.util.AbstractList#indexOf()
C
CyC2018 已提交
2082

C
CyC2018 已提交
2083
## 11. 访问者(Visitor)
C
CyC2018 已提交
2084

C
CyC2018 已提交
2085
### Intent
C
CyC2018 已提交
2086

C
CyC2018 已提交
2087
为一个对象结构(比如组合结构)增加新能力。
C
CyC2018 已提交
2088

C
CyC2018 已提交
2089
### Class Diagram
C
CyC2018 已提交
2090

C
CyC2018 已提交
2091 2092 2093
- Visitor:访问者,为每一个 ConcreteElement 声明一个 visit 操作
- ConcreteVisitor:具体访问者,存储遍历过程中的累计结果
- ObjectStructure:对象结构,可以是组合结构,或者是一个集合。
C
CyC2018 已提交
2094

C
CyC2018 已提交
2095
<div align="center"> <img src="pics/ec923dc7-864c-47b0-a411-1f2c48d084de.png"/> </div><br>
C
CyC2018 已提交
2096

C
CyC2018 已提交
2097
### Implementation
C
CyC2018 已提交
2098 2099

```java
C
CyC2018 已提交
2100 2101
public interface Element {
    void accept(Visitor visitor);
C
CyC2018 已提交
2102 2103 2104 2105
}
```

```java
C
CyC2018 已提交
2106
class CustomerGroup {
C
CyC2018 已提交
2107

C
CyC2018 已提交
2108
    private List<Customer> customers = new ArrayList<>();
C
CyC2018 已提交
2109

C
CyC2018 已提交
2110 2111 2112 2113 2114
    void accept(Visitor visitor) {
        for (Customer customer : customers) {
            customer.accept(visitor);
        }
    }
C
CyC2018 已提交
2115

C
CyC2018 已提交
2116 2117 2118
    void addCustomer(Customer customer) {
        customers.add(customer);
    }
C
CyC2018 已提交
2119 2120 2121 2122
}
```

```java
C
CyC2018 已提交
2123
public class Customer implements Element {
C
CyC2018 已提交
2124

C
CyC2018 已提交
2125 2126
    private String name;
    private List<Order> orders = new ArrayList<>();
C
CyC2018 已提交
2127

C
CyC2018 已提交
2128 2129 2130
    Customer(String name) {
        this.name = name;
    }
C
CyC2018 已提交
2131

C
CyC2018 已提交
2132 2133 2134
    String getName() {
        return name;
    }
C
CyC2018 已提交
2135

C
CyC2018 已提交
2136 2137 2138
    void addOrder(Order order) {
        orders.add(order);
    }
C
CyC2018 已提交
2139

C
CyC2018 已提交
2140 2141 2142 2143 2144 2145
    public void accept(Visitor visitor) {
        visitor.visit(this);
        for (Order order : orders) {
            order.accept(visitor);
        }
    }
C
CyC2018 已提交
2146 2147 2148 2149
}
```

```java
C
CyC2018 已提交
2150
public class Order implements Element {
C
CyC2018 已提交
2151

C
CyC2018 已提交
2152 2153
    private String name;
    private List<Item> items = new ArrayList();
C
CyC2018 已提交
2154

C
CyC2018 已提交
2155 2156 2157
    Order(String name) {
        this.name = name;
    }
C
CyC2018 已提交
2158

C
CyC2018 已提交
2159 2160 2161 2162
    Order(String name, String itemName) {
        this.name = name;
        this.addItem(new Item(itemName));
    }
C
CyC2018 已提交
2163

C
CyC2018 已提交
2164 2165 2166
    String getName() {
        return name;
    }
C
CyC2018 已提交
2167

C
CyC2018 已提交
2168 2169 2170
    void addItem(Item item) {
        items.add(item);
    }
C
CyC2018 已提交
2171

C
CyC2018 已提交
2172 2173
    public void accept(Visitor visitor) {
        visitor.visit(this);
C
CyC2018 已提交
2174

C
CyC2018 已提交
2175 2176 2177 2178
        for (Item item : items) {
            item.accept(visitor);
        }
    }
C
CyC2018 已提交
2179 2180 2181 2182
}
```

```java
C
CyC2018 已提交
2183
public class Item implements Element {
C
CyC2018 已提交
2184

C
CyC2018 已提交
2185
    private String name;
C
CyC2018 已提交
2186

C
CyC2018 已提交
2187 2188 2189
    Item(String name) {
        this.name = name;
    }
C
CyC2018 已提交
2190

C
CyC2018 已提交
2191 2192 2193
    String getName() {
        return name;
    }
C
CyC2018 已提交
2194

C
CyC2018 已提交
2195 2196 2197
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
C
CyC2018 已提交
2198 2199 2200 2201
}
```

```java
C
CyC2018 已提交
2202 2203
public interface Visitor {
    void visit(Customer customer);
C
CyC2018 已提交
2204

C
CyC2018 已提交
2205
    void visit(Order order);
C
CyC2018 已提交
2206

C
CyC2018 已提交
2207
    void visit(Item item);
C
CyC2018 已提交
2208 2209 2210 2211
}
```

```java
C
CyC2018 已提交
2212
public class GeneralReport implements Visitor {
C
CyC2018 已提交
2213

C
CyC2018 已提交
2214 2215 2216
    private int customersNo;
    private int ordersNo;
    private int itemsNo;
C
CyC2018 已提交
2217

C
CyC2018 已提交
2218 2219 2220 2221
    public void visit(Customer customer) {
        System.out.println(customer.getName());
        customersNo++;
    }
C
CyC2018 已提交
2222

C
CyC2018 已提交
2223 2224 2225 2226
    public void visit(Order order) {
        System.out.println(order.getName());
        ordersNo++;
    }
C
CyC2018 已提交
2227

C
CyC2018 已提交
2228 2229 2230 2231
    public void visit(Item item) {
        System.out.println(item.getName());
        itemsNo++;
    }
C
CyC2018 已提交
2232

C
CyC2018 已提交
2233 2234 2235 2236 2237
    public void displayResults() {
        System.out.println("Number of customers: " + customersNo);
        System.out.println("Number of orders:    " + ordersNo);
        System.out.println("Number of items:     " + itemsNo);
    }
C
CyC2018 已提交
2238 2239 2240 2241
}
```

```java
C
CyC2018 已提交
2242 2243 2244 2245 2246 2247
public class Client {
    public static void main(String[] args) {
        Customer customer1 = new Customer("customer1");
        customer1.addOrder(new Order("order1", "item1"));
        customer1.addOrder(new Order("order2", "item1"));
        customer1.addOrder(new Order("order3", "item1"));
C
CyC2018 已提交
2248

C
CyC2018 已提交
2249 2250 2251 2252 2253 2254
        Order order = new Order("order_a");
        order.addItem(new Item("item_a1"));
        order.addItem(new Item("item_a2"));
        order.addItem(new Item("item_a3"));
        Customer customer2 = new Customer("customer2");
        customer2.addOrder(order);
C
CyC2018 已提交
2255

C
CyC2018 已提交
2256 2257 2258
        CustomerGroup customers = new CustomerGroup();
        customers.addCustomer(customer1);
        customers.addCustomer(customer2);
C
CyC2018 已提交
2259

C
CyC2018 已提交
2260 2261 2262 2263
        GeneralReport visitor = new GeneralReport();
        customers.accept(visitor);
        visitor.displayResults();
    }
C
CyC2018 已提交
2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279
}
```

```html
customer1
order1
item1
order2
item1
order3
item1
customer2
order_a
item_a1
item_a2
item_a3
C
CyC2018 已提交
2280 2281 2282
Number of customers: 2
Number of orders:    4
Number of items:     6
C
CyC2018 已提交
2283
```
C
CyC2018 已提交
2284

C
CyC2018 已提交
2285
### JDK
C
CyC2018 已提交
2286

C
CyC2018 已提交
2287 2288
- javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
- javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor
C
CyC2018 已提交
2289

C
CyC2018 已提交
2290
## 12. 空对象(Null)
C
CyC2018 已提交
2291

C
CyC2018 已提交
2292
### Intent
C
CyC2018 已提交
2293

C
CyC2018 已提交
2294
使用什么都不做的空对象来代替 NULL。
C
CyC2018 已提交
2295

C
CyC2018 已提交
2296
一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。
C
CyC2018 已提交
2297

C
CyC2018 已提交
2298
### Class Diagram
C
CyC2018 已提交
2299

C
CyC2018 已提交
2300
<div align="center"> <img src="pics/dd3b289c-d90e-44a6-a44c-4880517eb1de.png"/> </div><br>
C
CyC2018 已提交
2301

C
CyC2018 已提交
2302
### Implementation
C
CyC2018 已提交
2303 2304

```java
C
CyC2018 已提交
2305 2306
public abstract class AbstractOperation {
    abstract void request();
C
CyC2018 已提交
2307 2308 2309 2310
}
```

```java
C
CyC2018 已提交
2311 2312 2313 2314 2315
public class RealOperation extends AbstractOperation {
    @Override
    void request() {
        System.out.println("do something");
    }
C
CyC2018 已提交
2316 2317 2318 2319
}
```

```java
C
CyC2018 已提交
2320 2321 2322 2323 2324
public class NullOperation extends AbstractOperation{
    @Override
    void request() {
        // do nothing
    }
C
CyC2018 已提交
2325 2326 2327 2328
}
```

```java
C
CyC2018 已提交
2329 2330 2331 2332 2333
public class Client {
    public static void main(String[] args) {
        AbstractOperation abstractOperation = func(-1);
        abstractOperation.request();
    }
C
CyC2018 已提交
2334

C
CyC2018 已提交
2335 2336 2337 2338 2339 2340
    public static AbstractOperation func(int para) {
        if (para < 0) {
            return new NullOperation();
        }
        return new RealOperation();
    }
C
CyC2018 已提交
2341 2342 2343
}
```

C
CyC2018 已提交
2344
# 四、结构型
C
CyC2018 已提交
2345

C
CyC2018 已提交
2346
## 1. 适配器(Adapter)
C
CyC2018 已提交
2347

C
CyC2018 已提交
2348
### Intent
C
CyC2018 已提交
2349 2350 2351

把一个类接口转换成另一个用户需要的接口。

C
CyC2018 已提交
2352
<div align="center"> <img src="pics/3d5b828e-5c4d-48d8-a440-281e4a8e1c92.png"/> </div><br>
C
CyC2018 已提交
2353

C
CyC2018 已提交
2354
### Class Diagram
C
CyC2018 已提交
2355

C
CyC2018 已提交
2356
<div align="center"> <img src="pics/0889c0b4-07b4-45fc-873c-e0e16b97f67d.png"/> </div><br>
C
CyC2018 已提交
2357

C
CyC2018 已提交
2358
### Implementation
C
CyC2018 已提交
2359

C
CyC2018 已提交
2360
鸭子(Duck)和火鸡(Turkey)拥有不同的叫声,Duck 的叫声调用 quack() 方法,而 Turkey 调用 gobble() 方法。
C
CyC2018 已提交
2361

C
CyC2018 已提交
2362
要求将 Turkey 的 gobble() 方法适配成 Duck 的 quack() 方法,从而让火鸡冒充鸭子!
C
CyC2018 已提交
2363 2364

```java
C
CyC2018 已提交
2365 2366
public interface Duck {
    void quack();
C
CyC2018 已提交
2367 2368 2369 2370
}
```

```java
C
CyC2018 已提交
2371 2372
public interface Turkey {
    void gobble();
C
CyC2018 已提交
2373 2374 2375 2376
}
```

```java
C
CyC2018 已提交
2377 2378 2379 2380 2381
public class WildTurkey implements Turkey {
    @Override
    public void gobble() {
        System.out.println("gobble!");
    }
C
CyC2018 已提交
2382 2383 2384 2385
}
```

```java
C
CyC2018 已提交
2386 2387
public class TurkeyAdapter implements Duck {
    Turkey turkey;
C
CyC2018 已提交
2388

C
CyC2018 已提交
2389 2390 2391
    public TurkeyAdapter(Turkey turkey) {
        this.turkey = turkey;
    }
C
CyC2018 已提交
2392

C
CyC2018 已提交
2393 2394 2395 2396
    @Override
    public void quack() {
        turkey.gobble();
    }
C
CyC2018 已提交
2397 2398 2399 2400
}
```

```java
C
CyC2018 已提交
2401 2402 2403 2404 2405 2406
public class Client {
    public static void main(String[] args) {
        Turkey turkey = new WildTurkey();
        Duck duck = new TurkeyAdapter(turkey);
        duck.quack();
    }
C
CyC2018 已提交
2407 2408 2409
}
```

C
CyC2018 已提交
2410
### JDK
C
CyC2018 已提交
2411

C
CyC2018 已提交
2412 2413 2414 2415
- [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
- [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-)
- [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-)
- [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-)
C
CyC2018 已提交
2416

C
CyC2018 已提交
2417
## 2. 桥接(Bridge)
C
CyC2018 已提交
2418

C
CyC2018 已提交
2419
### Intent
C
CyC2018 已提交
2420 2421 2422

将抽象与实现分离开来,使它们可以独立变化。

C
CyC2018 已提交
2423
### Class Diagram
C
CyC2018 已提交
2424

C
CyC2018 已提交
2425 2426
- Abstraction:定义抽象类的接口
- Implementor:定义实现类接口
C
CyC2018 已提交
2427

C
CyC2018 已提交
2428
<div align="center"> <img src="pics/c2cbf5d2-82af-4c78-bd43-495da5adf55f.png"/> </div><br>
C
CyC2018 已提交
2429

C
CyC2018 已提交
2430
### Implementation
C
CyC2018 已提交
2431

C
CyC2018 已提交
2432
RemoteControl 表示遥控器,指代 Abstraction。
C
CyC2018 已提交
2433

C
CyC2018 已提交
2434
TV 表示电视,指代 Implementor。
C
CyC2018 已提交
2435 2436 2437 2438

桥接模式将遥控器和电视分离开来,从而可以独立改变遥控器或者电视的实现。

```java
C
CyC2018 已提交
2439 2440
public abstract class TV {
    public abstract void on();
C
CyC2018 已提交
2441

C
CyC2018 已提交
2442
    public abstract void off();
C
CyC2018 已提交
2443

C
CyC2018 已提交
2444
    public abstract void tuneChannel();
C
CyC2018 已提交
2445 2446 2447 2448
}
```

```java
C
CyC2018 已提交
2449 2450 2451 2452 2453
public class Sony extends TV {
    @Override
    public void on() {
        System.out.println("Sony.on()");
    }
C
CyC2018 已提交
2454

C
CyC2018 已提交
2455 2456 2457 2458
    @Override
    public void off() {
        System.out.println("Sony.off()");
    }
C
CyC2018 已提交
2459

C
CyC2018 已提交
2460 2461 2462 2463
    @Override
    public void tuneChannel() {
        System.out.println("Sony.tuneChannel()");
    }
C
CyC2018 已提交
2464 2465 2466 2467
}
```

```java
C
CyC2018 已提交
2468 2469 2470 2471 2472
public class RCA extends TV {
    @Override
    public void on() {
        System.out.println("RCA.on()");
    }
C
CyC2018 已提交
2473

C
CyC2018 已提交
2474 2475 2476 2477
    @Override
    public void off() {
        System.out.println("RCA.off()");
    }
C
CyC2018 已提交
2478

C
CyC2018 已提交
2479 2480 2481 2482
    @Override
    public void tuneChannel() {
        System.out.println("RCA.tuneChannel()");
    }
C
CyC2018 已提交
2483 2484 2485 2486
}
```

```java
C
CyC2018 已提交
2487 2488
public abstract class RemoteControl {
    protected TV tv;
C
CyC2018 已提交
2489

C
CyC2018 已提交
2490 2491 2492
    public RemoteControl(TV tv) {
        this.tv = tv;
    }
C
CyC2018 已提交
2493

C
CyC2018 已提交
2494
    public abstract void on();
C
CyC2018 已提交
2495

C
CyC2018 已提交
2496
    public abstract void off();
C
CyC2018 已提交
2497

C
CyC2018 已提交
2498
    public abstract void tuneChannel();
C
CyC2018 已提交
2499 2500 2501 2502
}
```

```java
C
CyC2018 已提交
2503 2504 2505 2506
public class ConcreteRemoteControl1 extends RemoteControl {
    public ConcreteRemoteControl1(TV tv) {
        super(tv);
    }
C
CyC2018 已提交
2507

C
CyC2018 已提交
2508 2509 2510 2511 2512
    @Override
    public void on() {
        System.out.println("ConcreteRemoteControl1.on()");
        tv.on();
    }
C
CyC2018 已提交
2513

C
CyC2018 已提交
2514 2515 2516 2517 2518
    @Override
    public void off() {
        System.out.println("ConcreteRemoteControl1.off()");
        tv.off();
    }
C
CyC2018 已提交
2519

C
CyC2018 已提交
2520 2521 2522 2523 2524
    @Override
    public void tuneChannel() {
        System.out.println("ConcreteRemoteControl1.tuneChannel()");
        tv.tuneChannel();
    }
C
CyC2018 已提交
2525 2526 2527 2528
}
```

```java
C
CyC2018 已提交
2529 2530 2531 2532
public class ConcreteRemoteControl2 extends RemoteControl {
    public ConcreteRemoteControl2(TV tv) {
        super(tv);
    }
C
CyC2018 已提交
2533

C
CyC2018 已提交
2534 2535 2536 2537 2538
    @Override
    public void on() {
        System.out.println("ConcreteRemoteControl2.on()");
        tv.on();
    }
C
CyC2018 已提交
2539

C
CyC2018 已提交
2540 2541 2542 2543 2544
    @Override
    public void off() {
        System.out.println("ConcreteRemoteControl2.off()");
        tv.off();
    }
C
CyC2018 已提交
2545

C
CyC2018 已提交
2546 2547 2548 2549 2550
    @Override
    public void tuneChannel() {
        System.out.println("ConcreteRemoteControl2.tuneChannel()");
        tv.tuneChannel();
    }
C
CyC2018 已提交
2551 2552 2553 2554
}
```

```java
C
CyC2018 已提交
2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
public class Client {
    public static void main(String[] args) {
        RemoteControl remoteControl1 = new ConcreteRemoteControl1(new RCA());
        remoteControl1.on();
        remoteControl1.off();
        remoteControl1.tuneChannel();
        RemoteControl remoteControl2 = new ConcreteRemoteControl2(new Sony());
         remoteControl2.on();
         remoteControl2.off();
         remoteControl2.tuneChannel();
    }
C
CyC2018 已提交
2566 2567 2568
}
```

C
CyC2018 已提交
2569
### JDK
C
CyC2018 已提交
2570

C
CyC2018 已提交
2571 2572
- AWT (It provides an abstraction layer which maps onto the native OS the windowing support.)
- JDBC
C
CyC2018 已提交
2573

C
CyC2018 已提交
2574
## 3. 组合(Composite)
C
CyC2018 已提交
2575

C
CyC2018 已提交
2576
### Intent
C
CyC2018 已提交
2577

C
CyC2018 已提交
2578 2579
将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。

C
CyC2018 已提交
2580
### Class Diagram
C
CyC2018 已提交
2581 2582 2583 2584 2585

组件(Component)类是组合类(Composite)和叶子类(Leaf)的父类,可以把组合类看成是树的中间节点。

组合对象拥有一个或者多个组件对象,因此组合对象的操作可以委托给组件对象去处理,而组件对象可以是另一个组合对象或者叶子对象。

C
CyC2018 已提交
2586
<div align="center"> <img src="pics/77931a4b-72ba-4016-827d-84b9a6845a51.png"/> </div><br>
C
CyC2018 已提交
2587

C
CyC2018 已提交
2588
### Implementation
C
CyC2018 已提交
2589 2590

```java
C
CyC2018 已提交
2591 2592
public abstract class Component {
    protected String name;
C
CyC2018 已提交
2593

C
CyC2018 已提交
2594 2595 2596
    public Component(String name) {
        this.name = name;
    }
C
CyC2018 已提交
2597

C
CyC2018 已提交
2598 2599 2600
    public void print() {
        print(0);
    }
C
CyC2018 已提交
2601

C
CyC2018 已提交
2602
    abstract void print(int level);
C
CyC2018 已提交
2603

C
CyC2018 已提交
2604
    abstract public void add(Component component);
C
CyC2018 已提交
2605

C
CyC2018 已提交
2606
    abstract public void remove(Component component);
C
CyC2018 已提交
2607 2608 2609 2610
}
```

```java
C
CyC2018 已提交
2611
public class Composite extends Component {
C
CyC2018 已提交
2612

C
CyC2018 已提交
2613
    private List<Component> child;
C
CyC2018 已提交
2614

C
CyC2018 已提交
2615 2616 2617 2618
    public Composite(String name) {
        super(name);
        child = new ArrayList<>();
    }
C
CyC2018 已提交
2619

C
CyC2018 已提交
2620 2621 2622 2623 2624 2625 2626 2627 2628 2629
    @Override
    void print(int level) {
        for (int i = 0; i < level; i++) {
            System.out.print("--");
        }
        System.out.println("Composite:" + name);
        for (Component component : child) {
            component.print(level + 1);
        }
    }
C
CyC2018 已提交
2630

C
CyC2018 已提交
2631 2632 2633 2634
    @Override
    public void add(Component component) {
        child.add(component);
    }
C
CyC2018 已提交
2635

C
CyC2018 已提交
2636 2637 2638 2639
    @Override
    public void remove(Component component) {
        child.remove(component);
    }
C
CyC2018 已提交
2640 2641 2642 2643
}
```

```java
C
CyC2018 已提交
2644 2645 2646 2647
public class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }
C
CyC2018 已提交
2648

C
CyC2018 已提交
2649 2650 2651 2652 2653 2654 2655
    @Override
    void print(int level) {
        for (int i = 0; i < level; i++) {
            System.out.print("--");
        }
        System.out.println("left:" + name);
    }
C
CyC2018 已提交
2656

C
CyC2018 已提交
2657 2658 2659 2660
    @Override
    public void add(Component component) {
        throw new UnsupportedOperationException(); // 牺牲透明性换取单一职责原则,这样就不用考虑是叶子节点还是组合节点
    }
C
CyC2018 已提交
2661

C
CyC2018 已提交
2662 2663 2664 2665
    @Override
    public void remove(Component component) {
        throw new UnsupportedOperationException();
    }
C
CyC2018 已提交
2666 2667 2668 2669
}
```

```java
C
CyC2018 已提交
2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686
public class Client {
    public static void main(String[] args) {
        Composite root = new Composite("root");
        Component node1 = new Leaf("1");
        Component node2 = new Composite("2");
        Component node3 = new Leaf("3");
        root.add(node1);
        root.add(node2);
        root.add(node3);
        Component node21 = new Leaf("21");
        Component node22 = new Composite("22");
        node2.add(node21);
        node2.add(node22);
        Component node221 = new Leaf("221");
        node22.add(node221);
        root.print();
    }
C
CyC2018 已提交
2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698
}
```

```html
Composite:root
--left:1
--Composite:2
----left:21
----Composite:22
------left:221
--left:3
```
C
CyC2018 已提交
2699

C
CyC2018 已提交
2700
### JDK
C
CyC2018 已提交
2701

C
CyC2018 已提交
2702 2703 2704 2705 2706
- javax.swing.JComponent#add(Component)
- java.awt.Container#add(Component)
- java.util.Map#putAll(Map)
- java.util.List#addAll(Collection)
- java.util.Set#addAll(Collection)
C
CyC2018 已提交
2707

C
CyC2018 已提交
2708
## 4. 装饰(Decorator)
C
CyC2018 已提交
2709

C
CyC2018 已提交
2710
### Intent
C
CyC2018 已提交
2711 2712 2713

为对象动态添加功能。

C
CyC2018 已提交
2714
### Class Diagram
C
CyC2018 已提交
2715

C
CyC2018 已提交
2716
装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。
C
CyC2018 已提交
2717

C
CyC2018 已提交
2718
<div align="center"> <img src="pics/137c593d-0a9e-47b8-a9e6-b71f540b82dd.png"/> </div><br>
C
CyC2018 已提交
2719

C
CyC2018 已提交
2720
### Implementation
C
CyC2018 已提交
2721 2722 2723

设计不同种类的饮料,饮料可以添加配料,比如可以添加牛奶,并且支持动态添加新配料。每增加一种配料,该饮料的价格就会增加,要求计算一种饮料的价格。

C
CyC2018 已提交
2724
下图表示在 DarkRoast 饮料上新增新添加 Mocha 配料,之后又添加了 Whip 配料。DarkRoast 被 Mocha 包裹,Mocha 又被 Whip 包裹。它们都继承自相同父类,都有 cost() 方法,外层类的 cost() 方法调用了内层类的 cost() 方法。
C
CyC2018 已提交
2725

C
CyC2018 已提交
2726
<div align="center"> <img src="pics/c9cfd600-bc91-4f3a-9f99-b42f88a5bb24.jpg" width="600"/> </div><br>
C
CyC2018 已提交
2727 2728

```java
C
CyC2018 已提交
2729 2730
public interface Beverage {
    double cost();
C
CyC2018 已提交
2731 2732 2733 2734
}
```

```java
C
CyC2018 已提交
2735 2736 2737 2738 2739
public class DarkRoast implements Beverage {
    @Override
    public double cost() {
        return 1;
    }
C
CyC2018 已提交
2740 2741 2742 2743
}
```

```java
C
CyC2018 已提交
2744 2745 2746 2747 2748
public class HouseBlend implements Beverage {
    @Override
    public double cost() {
        return 1;
    }
C
CyC2018 已提交
2749 2750 2751 2752
}
```

```java
C
CyC2018 已提交
2753 2754
public abstract class CondimentDecorator implements Beverage {
    protected Beverage beverage;
C
CyC2018 已提交
2755 2756 2757 2758
}
```

```java
C
CyC2018 已提交
2759
public class Milk extends CondimentDecorator {
C
CyC2018 已提交
2760

C
CyC2018 已提交
2761 2762 2763
    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }
C
CyC2018 已提交
2764

C
CyC2018 已提交
2765 2766 2767 2768
    @Override
    public double cost() {
        return 1 + beverage.cost();
    }
C
CyC2018 已提交
2769 2770 2771 2772
}
```

```java
C
CyC2018 已提交
2773
public class Mocha extends CondimentDecorator {
C
CyC2018 已提交
2774

C
CyC2018 已提交
2775 2776 2777
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
C
CyC2018 已提交
2778

C
CyC2018 已提交
2779 2780 2781 2782
    @Override
    public double cost() {
        return 1 + beverage.cost();
    }
C
CyC2018 已提交
2783 2784 2785 2786
}
```

```java
C
CyC2018 已提交
2787
public class Client {
C
CyC2018 已提交
2788

C
CyC2018 已提交
2789 2790 2791 2792 2793 2794
    public static void main(String[] args) {
        Beverage beverage = new HouseBlend();
        beverage = new Mocha(beverage);
        beverage = new Milk(beverage);
        System.out.println(beverage.cost());
    }
C
CyC2018 已提交
2795 2796 2797 2798 2799 2800 2801
}
```

```html
3.0
```

C
CyC2018 已提交
2802
### 设计原则
C
CyC2018 已提交
2803

C
CyC2018 已提交
2804 2805 2806
类应该对扩展开放,对修改关闭:也就是添加新功能时不需要修改代码。饮料可以动态添加新的配料,而不需要去修改饮料的代码。

不可能把所有的类设计成都满足这一原则,应当把该原则应用于最有可能发生改变的地方。
C
CyC2018 已提交
2807

C
CyC2018 已提交
2808
### JDK
C
CyC2018 已提交
2809

C
CyC2018 已提交
2810 2811 2812 2813 2814
- java.io.BufferedInputStream(InputStream)
- java.io.DataInputStream(InputStream)
- java.io.BufferedOutputStream(OutputStream)
- java.util.zip.ZipOutputStream(OutputStream)
- java.util.Collections#checked[List|Map|Set|SortedSet|SortedMap]()
C
CyC2018 已提交
2815

C
CyC2018 已提交
2816
## 5. 外观(Facade)
C
CyC2018 已提交
2817

C
CyC2018 已提交
2818
### Intent
C
CyC2018 已提交
2819 2820 2821

提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。

C
CyC2018 已提交
2822
### Class Diagram
C
CyC2018 已提交
2823

C
CyC2018 已提交
2824
<div align="center"> <img src="pics/f9978fa6-9f49-4a0f-8540-02d269ac448f.png"/> </div><br>
C
CyC2018 已提交
2825

C
CyC2018 已提交
2826
### Implementation
C
CyC2018 已提交
2827

C
CyC2018 已提交
2828
观看电影需要操作很多电器,使用外观模式实现一键看电影功能。
C
CyC2018 已提交
2829

C
CyC2018 已提交
2830
```java
C
CyC2018 已提交
2831 2832 2833 2834
public class SubSystem {
    public void turnOnTV() {
        System.out.println("turnOnTV()");
    }
C
CyC2018 已提交
2835

C
CyC2018 已提交
2836 2837 2838
    public void setCD(String cd) {
        System.out.println("setCD( " + cd + " )");
    }
C
CyC2018 已提交
2839

C
CyC2018 已提交
2840 2841 2842
    public void startWatching(){
        System.out.println("startWatching()");
    }
C
CyC2018 已提交
2843 2844 2845 2846
}
```

```java
C
CyC2018 已提交
2847 2848
public class Facade {
    private SubSystem subSystem = new SubSystem();
C
CyC2018 已提交
2849

C
CyC2018 已提交
2850 2851 2852 2853 2854
    public void watchMovie() {
        subSystem.turnOnTV();
        subSystem.setCD("a movie");
        subSystem.startWatching();
    }
C
CyC2018 已提交
2855 2856 2857 2858
}
```

```java
C
CyC2018 已提交
2859 2860 2861 2862 2863
public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.watchMovie();
    }
C
CyC2018 已提交
2864 2865 2866
}
```

C
CyC2018 已提交
2867
### 设计原则
C
CyC2018 已提交
2868

C
CyC2018 已提交
2869
最少知识原则:只和你的密友谈话。也就是说客户对象所需要交互的对象应当尽可能少。
C
CyC2018 已提交
2870

C
CyC2018 已提交
2871
## 6. 享元(Flyweight)
C
CyC2018 已提交
2872

C
CyC2018 已提交
2873
### Intent
C
CyC2018 已提交
2874

C
CyC2018 已提交
2875 2876
利用共享的方式来支持大量细粒度的对象,这些对象一部分内部状态是相同的。

C
CyC2018 已提交
2877
### Class Diagram
C
CyC2018 已提交
2878

C
CyC2018 已提交
2879 2880 2881
- Flyweight:享元对象
- IntrinsicState:内部状态,享元对象共享内部状态
- ExtrinsicState:外部状态,每个享元对象的外部状态不同
C
CyC2018 已提交
2882

C
CyC2018 已提交
2883
<div align="center"> <img src="pics/d52270b4-9097-4667-9f18-f405fc661c99.png"/> </div><br>
C
CyC2018 已提交
2884

C
CyC2018 已提交
2885
### Implementation
C
CyC2018 已提交
2886 2887

```java
C
CyC2018 已提交
2888 2889
public interface Flyweight {
    void doOperation(String extrinsicState);
C
CyC2018 已提交
2890 2891 2892 2893
}
```

```java
C
CyC2018 已提交
2894
public class ConcreteFlyweight implements Flyweight {
C
CyC2018 已提交
2895

C
CyC2018 已提交
2896
    private String intrinsicState;
C
CyC2018 已提交
2897

C
CyC2018 已提交
2898 2899 2900
    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }
C
CyC2018 已提交
2901

C
CyC2018 已提交
2902 2903 2904 2905 2906 2907
    @Override
    public void doOperation(String extrinsicState) {
        System.out.println("Object address: " + System.identityHashCode(this));
        System.out.println("IntrinsicState: " + intrinsicState);
        System.out.println("ExtrinsicState: " + extrinsicState);
    }
C
CyC2018 已提交
2908 2909 2910 2911
}
```

```java
C
CyC2018 已提交
2912
public class FlyweightFactory {
C
CyC2018 已提交
2913

C
CyC2018 已提交
2914
    private HashMap<String, Flyweight> flyweights = new HashMap<>();
C
CyC2018 已提交
2915

C
CyC2018 已提交
2916 2917 2918 2919 2920 2921 2922
    Flyweight getFlyweight(String intrinsicState) {
        if (!flyweights.containsKey(intrinsicState)) {
            Flyweight flyweight = new ConcreteFlyweight(intrinsicState);
            flyweights.put(intrinsicState, flyweight);
        }
        return flyweights.get(intrinsicState);
    }
C
CyC2018 已提交
2923 2924 2925 2926
}
```

```java
C
CyC2018 已提交
2927
public class Client {
C
CyC2018 已提交
2928

C
CyC2018 已提交
2929 2930 2931 2932 2933 2934 2935
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight flyweight1 = factory.getFlyweight("aa");
        Flyweight flyweight2 = factory.getFlyweight("aa");
        flyweight1.doOperation("x");
        flyweight2.doOperation("y");
    }
C
CyC2018 已提交
2936 2937 2938 2939
}
```

```html
C
CyC2018 已提交
2940 2941 2942 2943 2944 2945
Object address: 1163157884
IntrinsicState: aa
ExtrinsicState: x
Object address: 1163157884
IntrinsicState: aa
ExtrinsicState: y
C
CyC2018 已提交
2946
```
C
CyC2018 已提交
2947

C
CyC2018 已提交
2948
### JDK
C
CyC2018 已提交
2949

C
CyC2018 已提交
2950
Java 利用缓存来加速大量小对象的访问时间。
C
CyC2018 已提交
2951

C
CyC2018 已提交
2952 2953 2954 2955
- java.lang.Integer#valueOf(int)
- java.lang.Boolean#valueOf(boolean)
- java.lang.Byte#valueOf(byte)
- java.lang.Character#valueOf(char)
C
CyC2018 已提交
2956

C
CyC2018 已提交
2957
## 7. 代理(Proxy)
C
CyC2018 已提交
2958

C
CyC2018 已提交
2959
### Intent
C
CyC2018 已提交
2960

C
CyC2018 已提交
2961
控制对其它对象的访问。
C
CyC2018 已提交
2962

C
CyC2018 已提交
2963
### Class Diagram
C
CyC2018 已提交
2964 2965 2966

代理有以下四类:

C
CyC2018 已提交
2967 2968 2969 2970
- 远程代理(Remote Proxy):控制对远程对象(不同地址空间)的访问,它负责将请求及其参数进行编码,并向不同地址空间中的对象发送已经编码的请求。
- 虚拟代理(Virtual Proxy):根据需要创建开销很大的对象,它可以缓存实体的附加信息,以便延迟对它的访问,例如在网站加载一个很大图片时,不能马上完成,可以用虚拟代理缓存图片的大小信息,然后生成一张临时图片代替原始图片。
- 保护代理(Protection Proxy):按权限控制对象的访问,它负责检查调用者是否具有实现一个请求所必须的访问权限。
- 智能代理(Smart Reference):取代了简单的指针,它在访问对象时执行一些附加操作:记录对象的引用次数;当第一次引用一个对象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其它对象不能改变它。
C
CyC2018 已提交
2971

C
CyC2018 已提交
2972
<div align="center"> <img src="pics/a6c20f60-5eba-427d-9413-352ada4b40fe.png"/> </div><br>
C
CyC2018 已提交
2973

C
CyC2018 已提交
2974
### Implementation
C
CyC2018 已提交
2975 2976 2977 2978

以下是一个虚拟代理的实现,模拟了图片延迟加载的情况下使用与图片大小相等的临时内容去替换原始图片,直到图片加载完成才将图片显示出来。

```java
C
CyC2018 已提交
2979 2980
public interface Image {
    void showImage();
C
CyC2018 已提交
2981 2982 2983 2984
}
```

```java
C
CyC2018 已提交
2985
public class HighResolutionImage implements Image {
C
CyC2018 已提交
2986

C
CyC2018 已提交
2987 2988 2989 2990
    private URL imageURL;
    private long startTime;
    private int height;
    private int width;
C
CyC2018 已提交
2991

C
CyC2018 已提交
2992 2993 2994
    public int getHeight() {
        return height;
    }
C
CyC2018 已提交
2995

C
CyC2018 已提交
2996 2997 2998
    public int getWidth() {
        return width;
    }
C
CyC2018 已提交
2999

C
CyC2018 已提交
3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069
    public HighResolutionImage(URL imageURL) {
        this.imageURL = imageURL;
        this.startTime = System.currentTimeMillis();
        this.width = 600;
        this.height = 600;
    }

    public boolean isLoad() {
        // 模拟图片加载,延迟 3s 加载完成
        long endTime = System.currentTimeMillis();
        return endTime - startTime > 3000;
    }

    @Override
    public void showImage() {
        System.out.println("Real Image: " + imageURL);
    }
}
```

```java
public class ImageProxy implements Image {

    private HighResolutionImage highResolutionImage;

    public ImageProxy(HighResolutionImage highResolutionImage) {
        this.highResolutionImage = highResolutionImage;
    }

    @Override
    public void showImage() {
        while (!highResolutionImage.isLoad()) {
            try {
                System.out.println("Temp Image: " + highResolutionImage.getWidth() + " " + highResolutionImage.getHeight());
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        highResolutionImage.showImage();
    }
}
```

```java
public class ImageViewer {

    public static void main(String[] args) throws Exception {
        String image = "http://image.jpg";
        URL url = new URL(image);
        HighResolutionImage highResolutionImage = new HighResolutionImage(url);
        ImageProxy imageProxy = new ImageProxy(highResolutionImage);
        imageProxy.showImage();
    }
}
```

### JDK

- java.lang.reflect.Proxy
- RMI

# 参考资料

- 弗里曼. Head First 设计模式 [M]. 中国电力出版社, 2007.
- Gamma E. 设计模式: 可复用面向对象软件的基础 [M]. 机械工业出版社, 2007.
- Bloch J. Effective java[M]. Addison-Wesley Professional, 2017.
- [Design Patterns](http://www.oodesign.com/)
- [Design patterns implemented in Java](http://java-design-patterns.com/)
- [The breakdown of design patterns in JDK](http://www.programering.com/a/MTNxAzMwATY.html)