设计模式.md 78.2 KB
Newer Older
C
CyC2018 已提交
1 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
<!-- 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 已提交
36

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
187

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

C
CyC2018 已提交
192

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

C
CyC2018 已提交
197

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

C
CyC2018 已提交
200 201 202 203 204 205 206 207
        // 单例测试
        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 已提交
208

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

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

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

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

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

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

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

C
CyC2018 已提交
242 243 244
- [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 已提交
245

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
287 288 289 290 291 292 293 294 295 296 297 298
    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 已提交
299 300 301
}
```

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
381 382 383 384 385 386 387
- [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 已提交
388

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```java
C
CyC2018 已提交
471 472 473 474 475 476 477
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 已提交
478 479 480
}
```

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

C
CyC2018 已提交
483 484 485
- [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 已提交
486

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
524 525 526 527 528 529 530 531 532 533 534
    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 已提交
535 536 537 538
}
```

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

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

```java
C
CyC2018 已提交
553 554 555 556 557 558 559 560 561
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 已提交
562 563 564 565 566 567
}
```

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

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

C
CyC2018 已提交
571 572 573 574 575
- [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 已提交
576

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

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

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

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

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

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

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

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

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

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

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

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

```java
C
CyC2018 已提交
617 618 619 620 621 622
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 已提交
623 624 625 626 627 628
}
```

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
655

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

C
CyC2018 已提交
660

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

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

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

C
CyC2018 已提交
672

C
CyC2018 已提交
673 674 675 676 677 678 679 680 681 682
    @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 已提交
683 684 685 686
}
```

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

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

C
CyC2018 已提交
693

C
CyC2018 已提交
694 695 696 697 698 699 700 701 702 703
    @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 已提交
704 705 706 707
}
```

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

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

C
CyC2018 已提交
713

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

C
CyC2018 已提交
719

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

C
CyC2018 已提交
724

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

C
CyC2018 已提交
730 731 732
```

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

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

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

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

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

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

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

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

C
CyC2018 已提交
762 763 764
- [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 已提交
765

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```java
C
CyC2018 已提交
874 875 876 877 878 879 880 881 882 883 884
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 已提交
885 886
}
```
C
CyC2018 已提交
887

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

C
CyC2018 已提交
890 891 892
- [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 已提交
893

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
930 931 932 933 934 935 936 937 938 939
    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 已提交
940 941 942 943
}
```

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

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

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

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

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

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

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

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

C
CyC2018 已提交
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
    /**
     * 构建解析树
     */
    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 已提交
995

C
CyC2018 已提交
996 997 998 999 1000 1001 1002
    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 已提交
1003 1004 1005 1006 1007 1008 1009 1010
}
```

```html
true
false
```

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

C
CyC2018 已提交
1013 1014 1015 1016
- [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 已提交
1017

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
1093 1094 1095 1096 1097 1098 1099
    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 已提交
1100 1101
}
```
C
CyC2018 已提交
1102

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

C
CyC2018 已提交
1105 1106
- [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 已提交
1107

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```java
C
CyC2018 已提交
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
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 已提交
1259 1260 1261 1262 1263 1264 1265 1266 1267
}
```

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

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

C
CyC2018 已提交
1271 1272 1273 1274 1275
- 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 已提交
1276

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```html
110
-273
110
```

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```java
C
CyC2018 已提交
1563 1564 1565 1566 1567
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 已提交
1568

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

```html
C
CyC2018 已提交
1576 1577 1578 1579
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 已提交
1580 1581
```

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

C
CyC2018 已提交
1584 1585 1586 1587
- [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 已提交
1588

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
    @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 已提交
1759 1760 1761 1762
}
```

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```html
C
CyC2018 已提交
1864 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
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 已提交
1894

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```java
C
CyC2018 已提交
2052 2053 2054 2055 2056 2057 2058 2059
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 已提交
2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073
}
```

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
2232 2233 2234 2235 2236
    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 已提交
2237 2238 2239 2240
}
```

```java
C
CyC2018 已提交
2241 2242 2243 2244 2245 2246
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 已提交
2247

C
CyC2018 已提交
2248 2249 2250 2251 2252 2253
        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 已提交
2254

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
2411 2412 2413 2414
- [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 已提交
2415

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```java
C
CyC2018 已提交
2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564
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 已提交
2565 2566 2567
}
```

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
2619 2620 2621 2622 2623 2624 2625 2626 2627 2628
    @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 已提交
2629

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

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

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

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

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

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

```java
C
CyC2018 已提交
2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685
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 已提交
2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697
}
```

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

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

C
CyC2018 已提交
2701 2702 2703 2704 2705
- 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 已提交
2706

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

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

为对象动态添加功能。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
2788 2789 2790 2791 2792 2793
    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 已提交
2794 2795 2796 2797 2798 2799 2800
}
```

```html
3.0
```

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

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

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

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

C
CyC2018 已提交
2809 2810 2811 2812 2813
- 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 已提交
2814

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
2901 2902 2903 2904 2905 2906
    @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 已提交
2907 2908 2909 2910
}
```

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

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

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

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

C
CyC2018 已提交
2928 2929 2930 2931 2932 2933 2934
    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 已提交
2935 2936 2937 2938
}
```

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

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

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

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

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

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

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

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

代理有以下四类:

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
2999 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
    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)
C
CyC2018 已提交
3069
<div align="center">欢迎关注公众号,获取最新文章!</div></br>
C
CyC2018 已提交
3070
<div align="center"><img width="150px" src="https://github.com/CyC2018/CS-Notes/raw/master/docs/_media/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>