├── .gitignore ├── AbstractFactory ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── lishuo │ ├── Test.java │ ├── factory │ ├── AbstractFactory.java │ ├── CNFactory.java │ └── USFactory.java │ ├── impl │ ├── CNApple.java │ ├── CNOrange.java │ ├── USApple.java │ └── USOrange.java │ └── interf │ ├── IApple.java │ └── IOrange.java ├── Adapter ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── lishuo │ ├── classmode │ ├── Adaptee.java │ ├── Adapter.java │ └── Target.java │ └── objectmode │ ├── Adaptee.java │ ├── Adapter.java │ └── Target.java ├── Observer ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── lishuo │ └── interf │ ├── Observer.java │ ├── Subject.java │ ├── TestObserver.java │ └── impl │ ├── CountObserver.java │ ├── CountObserver1.java │ └── CountSubject.java ├── README.md ├── SimpleFactory ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── lishuo │ ├── FruitFactory.java │ ├── Test.java │ ├── impl │ ├── Apple.java │ └── Orange.java │ └── interf │ └── IFruit.java ├── Singleton ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── lishuo │ └── sample │ ├── Singleton.java │ ├── Singleton1.java │ ├── Singleton2.java │ ├── Singleton3.java │ ├── Singleton4.java │ ├── Singleton5.java │ └── TestSingleton.java ├── TemplateMethod ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── lishuo │ └── templatemethod │ ├── CaffeineBeverage.java │ ├── Coffee.java │ ├── Tea.java │ └── Test.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Package Files # 4 | # /META-INF/lib/*.jar 5 | # *.jar 6 | *.war 7 | *.ear 8 | *.jar 9 | *~ 10 | .settings/ 11 | .svn/ 12 | target/ 13 | .classpath 14 | .DS_Store 15 | .settings 16 | .idea/ 17 | .project 18 | *.iml 19 | -------------------------------------------------------------------------------- /AbstractFactory/README.md: -------------------------------------------------------------------------------- 1 | #### JAVA设计模式系列: 2 | * [单例模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Singleton) 3 | * [观察者模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Observer) 4 | * [模板方法模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/TemplateMethod) 5 | * [简单工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/SimpleFactory) 6 | * [抽象工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/AbstractFactory) 7 | * [适配器模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Adapter) 8 | 9 | # 抽象工厂模式 10 | 11 | ### 定义 12 | 抽象工厂模式是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。在抽象工厂中,接口是负责创建相关对象的工厂,不需要显示指定他们的类。提供了一种创建对象的最佳方式。 13 | ### 角色 14 | * **抽象工厂类**:具体工厂必须实现或继承的父类,在`Java`中可以用抽象类或者接口实现。 15 | * **具体工厂类**:负责创建具体对象的类,包含具体的业务逻辑。 16 | * **抽象产品类**:工厂类所创建对象实例的父类。 17 | 18 | * **具体产品类**:工厂类创建的具体对象实例。 19 | 20 | ### 实现 21 | 这里简单写一个示例来实现抽象工厂模式。 22 | #### 类图 23 | ![](https://ww3.sinaimg.cn/large/006tKfTcgy1fe5t0ps9mcj30wm0bvwfp.jpg) 24 | 25 | * 这个类图描述的是抽象产品类与具体产品类之间的关系,从图中我们可以看出我们分别有`IOrange`和`IApple`两个接口,每个接口都有对应2个具体的实现类`CNOrange`、`USOrange`和`USApple`、`CNApple`。这里就构成了我们的抽象产品类与具体产品类。 26 | 27 | ![](https://ww3.sinaimg.cn/large/006tKfTcgy1fe5t5c6lzmj30s30fota1.jpg) 28 | 29 | * 这个类图描述抽象工厂类与具体工厂类之间的关系。抽象工厂类`AbstractFactory`分别有2个方法`getApple`、`getOrange`,交于具体工厂类`CNFactory`、`USFactory`实现具体逻辑。 30 | 31 | #### 抽象产品类 32 | 33 | ```java 34 | public interface IApple { 35 | 36 | void get(); 37 | } 38 | 39 | public interface IOrange { 40 | 41 | void get(); 42 | } 43 | ``` 44 | 45 | #### 具体产品类 46 | 47 | ```java 48 | public class CNApple implements IApple { 49 | 50 | public void get() { 51 | System.out.println("我是中国苹果。"); 52 | } 53 | } 54 | 55 | public class CNOrange implements IOrange { 56 | 57 | public void get() { 58 | System.out.println("我是中国橙子。"); 59 | } 60 | } 61 | 62 | public class USApple implements IApple { 63 | 64 | public void get() { 65 | System.out.println("我是美国苹果。"); 66 | } 67 | } 68 | 69 | public class USOrange implements IOrange { 70 | 71 | public void get() { 72 | System.out.println("我是美国橙子。"); 73 | } 74 | } 75 | ``` 76 | 定义了4个具体对象实例类。 77 | 78 | #### 抽象工厂类 79 | ```java 80 | public interface AbstractFactory { 81 | 82 | IApple getApple(); 83 | 84 | IOrange getOrange(); 85 | } 86 | 87 | ``` 88 | #### 具体工厂类 89 | 90 | ```java 91 | public class USFactory implements AbstractFactory { 92 | 93 | public IApple getApple() { 94 | return new USApple(); 95 | } 96 | 97 | public IOrange getOrange() { 98 | return new USOrange(); 99 | } 100 | 101 | } 102 | 103 | public class CNFactory implements AbstractFactory { 104 | public IApple getApple() { 105 | return new CNApple(); 106 | } 107 | 108 | public IOrange getOrange() { 109 | return new CNOrange(); 110 | } 111 | } 112 | ``` 113 | #### 测试 114 | 115 | ```java 116 | public static void main(String[] args) { 117 | AbstractFactory usFactory = new USFactory(); 118 | 119 | AbstractFactory cnFactory = new CNFactory(); 120 | 121 | usFactory.getApple().get(); 122 | usFactory.getOrange().get(); 123 | 124 | cnFactory.getApple().get(); 125 | cnFactory.getOrange().get(); 126 | 127 | } 128 | ``` 129 | 130 | 运行结果: 131 | ``` 132 | 我是美国苹果。 133 | 我是美国橙子。 134 | 我是中国苹果。 135 | 我是中国橙子。 136 | ``` 137 | 138 | #### 总结 139 | * 优点:可以将一个系列的产品族统一到一起创建; 140 | 141 | * 缺点:在产品族中扩展新的产品是很困难的,它需要修改抽象工厂的接口; 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /AbstractFactory/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | JavaDesignPattern 7 | me.lishuo 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | AbstractFactory 13 | 14 | 15 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/Test.java: -------------------------------------------------------------------------------- 1 | package me.lishuo; 2 | 3 | import me.lishuo.factory.AbstractFactory; 4 | import me.lishuo.factory.CNFactory; 5 | import me.lishuo.factory.USFactory; 6 | 7 | /** 8 | * Created by lis on 17/3/29. 9 | */ 10 | public class Test { 11 | 12 | public static void main(String[] args) { 13 | AbstractFactory usFactory = new USFactory(); 14 | 15 | AbstractFactory cnFactory = new CNFactory(); 16 | 17 | usFactory.getApple().get(); 18 | usFactory.getOrange().get(); 19 | 20 | cnFactory.getApple().get(); 21 | cnFactory.getOrange().get(); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/factory/AbstractFactory.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.factory; 2 | 3 | import me.lishuo.interf.IApple; 4 | import me.lishuo.interf.IOrange; 5 | 6 | /** 7 | * Created by lis on 17/3/29. 8 | */ 9 | public interface AbstractFactory { 10 | 11 | IApple getApple(); 12 | 13 | IOrange getOrange(); 14 | } 15 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/factory/CNFactory.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.factory; 2 | 3 | import me.lishuo.impl.CNApple; 4 | import me.lishuo.impl.CNOrange; 5 | import me.lishuo.interf.IApple; 6 | import me.lishuo.interf.IOrange; 7 | 8 | /** 9 | * Created by lis on 17/3/29. 10 | */ 11 | public class CNFactory implements AbstractFactory { 12 | public IApple getApple() { 13 | return new CNApple(); 14 | } 15 | 16 | public IOrange getOrange() { 17 | return new CNOrange(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/factory/USFactory.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.factory; 2 | 3 | import me.lishuo.impl.USApple; 4 | import me.lishuo.impl.USOrange; 5 | import me.lishuo.interf.IApple; 6 | import me.lishuo.interf.IOrange; 7 | 8 | /** 9 | * Created by lis on 17/3/29. 10 | */ 11 | public class USFactory implements AbstractFactory { 12 | 13 | public IApple getApple() { 14 | return new USApple(); 15 | } 16 | 17 | public IOrange getOrange() { 18 | return new USOrange(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/impl/CNApple.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.impl; 2 | 3 | import me.lishuo.interf.IApple; 4 | 5 | /** 6 | * Created by lis on 17/3/29. 7 | */ 8 | public class CNApple implements IApple { 9 | 10 | public void get() { 11 | System.out.println("我是中国苹果。"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/impl/CNOrange.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.impl; 2 | 3 | import me.lishuo.interf.IOrange; 4 | 5 | /** 6 | * Created by lis on 17/3/29. 7 | */ 8 | public class CNOrange implements IOrange { 9 | 10 | public void get() { 11 | System.out.println("我是中国橙子。"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/impl/USApple.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.impl; 2 | 3 | import me.lishuo.interf.IApple; 4 | 5 | /** 6 | * Created by lis on 17/3/29. 7 | */ 8 | public class USApple implements IApple { 9 | 10 | public void get() { 11 | System.out.println("我是美国苹果。"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/impl/USOrange.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.impl; 2 | 3 | import me.lishuo.interf.IOrange; 4 | 5 | /** 6 | * Created by lis on 17/3/29. 7 | */ 8 | public class USOrange implements IOrange { 9 | 10 | public void get() { 11 | System.out.println("我是美国橙子。"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/interf/IApple.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.interf; 2 | 3 | /** 4 | * Created by lis on 17/3/29. 5 | */ 6 | public interface IApple { 7 | 8 | void get(); 9 | } 10 | -------------------------------------------------------------------------------- /AbstractFactory/src/main/java/me/lishuo/interf/IOrange.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.interf; 2 | 3 | /** 4 | * Created by lis on 17/3/29. 5 | */ 6 | public interface IOrange { 7 | 8 | void get(); 9 | } 10 | -------------------------------------------------------------------------------- /Adapter/README.md: -------------------------------------------------------------------------------- 1 | #### JAVA设计模式系列: 2 | * [单例模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Singleton) 3 | * [观察者模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Observer) 4 | * [模板方法模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/TemplateMethod) 5 | * [简单工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/SimpleFactory) 6 | * [抽象工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/AbstractFactory) 7 | * [适配器模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Adapter) 8 | 9 | # 适配器模式 10 | 11 | ### 概念 12 | 适配器模式是将类的一个接口转换成用户所期待的目标接口,使得原本因接口不匹配无法再一起工作的两个类一起工作。 13 | 14 | 生活中我们也会遇到这样的场景,如港版`iPhone`手机的充电器需要附加一个电源适配器才能够正常使用国内的电源插孔。 15 | 16 | 适配器模式有两种不同的形式:**类适配器模式**和**对象适配器模式**。 17 | ### 角色 18 | 19 | * 目标角色(`Target`):用户所期待的目标接口 20 | * 源角色(`Adaptee`): 需要被适配的类 21 | * 适配者角色(`Adapter`): 通过包装被适配的对象,将原接口转换为用户所期待的目标接口 22 | 23 | ### 实现 24 | 25 | #### 目标角色实现 26 | 27 | ```java 28 | public interface Target { 29 | 30 | void method1(); 31 | 32 | void method2(); 33 | 34 | } 35 | ``` 36 | 由`Target`接口实现目标角色,用户期待接口包含`method1`和`method2`两个方法。 37 | 38 | #### 源角色实现 39 | 40 | ```java 41 | public class Adaptee { 42 | 43 | public void method1(){ 44 | System.out.println("Adaptee method1"); 45 | } 46 | } 47 | ``` 48 | 49 | 源角色`Adaptee`类只实现了`method1`方法,这和用户所期望的不同。所以这里需要引入适配器,去转换成用户所期待的目标接口。 50 | 51 | #### 适配器实现 52 | 对于适配器的实现可分为两种形式:**类适配器模式**和**对象适配器模式**。 53 | 54 | ##### 类适配器模式 55 | 56 | ```java 57 | public class Adapter extends Adaptee implements Target { 58 | 59 | public void method2() { 60 | System.out.println("Adapter method2"); 61 | } 62 | } 63 | ``` 64 | `Adapter`类通过继承源角色`Adaptee`,复用了父类`method1`方法,并实现`Target`接口中`Adaptee`类中没有的方法`method2`。从而转换为用户期待目标的接口。 65 | 66 | ##### 对象适配器模式 67 | 68 | ```java 69 | 70 | public class Adapter implements Target { 71 | 72 | private Adaptee adaptee; 73 | 74 | public Adapter(Adaptee adaptee) { 75 | this.adaptee = adaptee; 76 | } 77 | 78 | public void method1() { 79 | adaptee.method1(); 80 | 81 | } 82 | 83 | public void method2() { 84 | System.out.println("Adapter method2"); 85 | } 86 | 87 | } 88 | ``` 89 | `Adapter`类直接实现了`Target`接口。`Adapter`类拥有一个`Adaptee`类的对象,将`method1`方法的实现委托给该对象实现。 90 | 91 | ### 总结 92 | 93 | 94 | #### 优点 95 | * 利用适配器后,使用这只需要调用一个接口即可。 96 | * 复用性强,复用了现有的类,无需修改源角色的类,使得目标接口和源角色解耦。 97 | * 更好的拓展性,一个适配器可以集成多个源角色来完成目标接口。 98 | 99 | #### 缺点 100 | 会使得系统之间的关系变的负责,过多的使用适配器模式,无疑增加代码阅读和理解成本。 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Adapter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | JavaDesignPattern 7 | me.lishuo 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | Adapter 13 | 14 | 15 | -------------------------------------------------------------------------------- /Adapter/src/main/java/me/lishuo/classmode/Adaptee.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.classmode; 2 | 3 | /** 4 | * Created by lis on 17/4/25. 5 | */ 6 | public class Adaptee { 7 | 8 | public void method1(){ 9 | System.out.println("Adaptee method1"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Adapter/src/main/java/me/lishuo/classmode/Adapter.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.classmode; 2 | 3 | /** 4 | * Created by lis on 17/4/25. 5 | */ 6 | public class Adapter extends Adaptee implements Target { 7 | 8 | public void method2() { 9 | System.out.println("Adapter method2"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Adapter/src/main/java/me/lishuo/classmode/Target.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.classmode; 2 | 3 | /** 4 | * Created by lis on 17/4/25. 5 | */ 6 | public interface Target { 7 | 8 | void method1(); 9 | 10 | void method2(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Adapter/src/main/java/me/lishuo/objectmode/Adaptee.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.objectmode; 2 | 3 | /** 4 | * Created by lis on 17/4/25. 5 | */ 6 | public class Adaptee { 7 | 8 | public void method1(){ 9 | System.out.println("Adaptee method1"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Adapter/src/main/java/me/lishuo/objectmode/Adapter.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.objectmode; 2 | 3 | /** 4 | * Created by lis on 17/4/25. 5 | */ 6 | public class Adapter implements Target { 7 | 8 | private Adaptee adaptee; 9 | 10 | public Adapter(Adaptee adaptee) { 11 | this.adaptee = adaptee; 12 | } 13 | 14 | public void method1() { 15 | adaptee.method1(); 16 | 17 | } 18 | 19 | public void method2() { 20 | System.out.println("Adapter method2"); 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Adapter/src/main/java/me/lishuo/objectmode/Target.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.objectmode; 2 | 3 | /** 4 | * Created by lis on 17/4/25. 5 | */ 6 | public interface Target { 7 | 8 | void method1(); 9 | 10 | void method2(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Observer/README.md: -------------------------------------------------------------------------------- 1 | #### JAVA设计模式系列: 2 | * [单例模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Singleton) 3 | * [观察者模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Observer) 4 | * [模板方法模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/TemplateMethod) 5 | * [简单工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/SimpleFactory) 6 | * [抽象工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/AbstractFactory) 7 | * [适配器模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Adapter) 8 | 9 | # 观察者模型 10 | 11 | ### 定义 12 | 也称作发布/订阅模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 13 | ### 角色 14 | 15 | * **抽象主题角色**:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。 16 | 17 | * **抽象观察者角色**:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。 18 | 19 | * **具体主题角色**:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。 20 | 21 | * **具体观察者角色**:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。 22 | 23 | ### 实现 24 | 这里简单写一个示例来实现观察者模式:定义某个主题的2个观察者,更新接口实现倒计时。 25 | 26 | #### 类图 27 | ![观察者模式类图](https://ww4.sinaimg.cn/large/006tNc79gy1fdk28ai1dzj311w0road0.jpg) 28 | #### 抽象主题代码 29 | 30 | ```java 31 | public interface Subject { 32 | 33 | void registerObserver(Observer observer); 34 | 35 | void removerObserver(Observer observer); 36 | 37 | void notifyObserver(); 38 | } 39 | ``` 40 | 定义3个方法,分别是增加观察者,删除观察者,通知观察者。 41 | 42 | #### 抽象观察者代码 43 | 44 | ```java 45 | public interface Observer { 46 | 47 | void update(Subject subject); 48 | } 49 | ``` 50 | 为所有具体的观察者定义一个接口,在得到主题的通知时调用`update`更新自己。 51 | #### 观察者A 52 | ```java 53 | public class CountObserver implements Observer { 54 | 55 | @Override 56 | public void update(Subject subject) { 57 | for (int i = 5; i > 0; i--){ 58 | System.out.println("CountObserver is working. i = " + i); 59 | } 60 | } 61 | } 62 | ``` 63 | #### 观察者B 64 | 65 | ```java 66 | public class CountObserver1 implements Observer { 67 | 68 | @Override 69 | public void update(Subject subject) { 70 | for (int i = 5; i > 0; i--){ 71 | System.out.println("CountObserver1 is working. i = " + i); 72 | } 73 | } 74 | } 75 | ``` 76 | #### 具体主题实现代码 77 | 78 | ```java 79 | public class CountSubject implements Subject { 80 | 81 | private List observerList; 82 | 83 | public CountSubject() { 84 | observerList = new ArrayList<>(); 85 | } 86 | 87 | public void registerObserver(Observer observer) { 88 | observerList.add(observer); 89 | } 90 | 91 | public void removerObserver(Observer observer) { 92 | observerList.remove(observer); 93 | } 94 | 95 | public void notifyObserver() { 96 | observerList.stream().forEach(o -> o.update(this)); 97 | } 98 | } 99 | ``` 100 | 维护了一个观察者的`list`并实现了对观察者的增加和删除。`notifyObserver`则通知所有的观察者。 101 | 102 | #### 测试类 103 | 104 | ```java 105 | public class TestObserver { 106 | 107 | public static void main(String[] args) { 108 | Subject subject = new CountSubject(); 109 | 110 | Observer observer = new CountObserver(); 111 | Observer observer1 = new CountObserver1(); 112 | 113 | subject.registerObserver(observer); 114 | subject.registerObserver(observer1); 115 | // subject.removerObserver(observer1); 116 | subject.notifyObserver(); 117 | } 118 | } 119 | ``` 120 | #### 运行结果 121 | 122 | ![运行结果](https://ww3.sinaimg.cn/large/006tNc79gy1fdk2iu6uhnj30l9098gn5.jpg) 123 | 124 | -------------------------------------------------------------------------------- /Observer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | JavaDesignPattern 7 | me.lishuo 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | Observer 13 | 14 | 15 | -------------------------------------------------------------------------------- /Observer/src/main/java/me/lishuo/interf/Observer.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.interf; 2 | 3 | /** 4 | * Created by lis on 17/3/12. 5 | */ 6 | public interface Observer { 7 | 8 | void update(Subject subject); 9 | } 10 | -------------------------------------------------------------------------------- /Observer/src/main/java/me/lishuo/interf/Subject.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.interf; 2 | 3 | /** 4 | * Created by lis on 17/3/12. 5 | */ 6 | public interface Subject { 7 | 8 | void registerObserver(Observer observer); 9 | 10 | void removerObserver(Observer observer); 11 | 12 | void notifyObserver(); 13 | } 14 | -------------------------------------------------------------------------------- /Observer/src/main/java/me/lishuo/interf/TestObserver.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.interf; 2 | 3 | import me.lishuo.interf.impl.CountObserver; 4 | import me.lishuo.interf.impl.CountObserver1; 5 | import me.lishuo.interf.impl.CountSubject; 6 | 7 | /** 8 | * Created by lis on 17/3/12. 9 | */ 10 | public class TestObserver { 11 | 12 | public static void main(String[] args) { 13 | Subject subject = new CountSubject(); 14 | 15 | Observer observer = new CountObserver(); 16 | Observer observer1 = new CountObserver1(); 17 | 18 | subject.registerObserver(observer); 19 | subject.registerObserver(observer1); 20 | // subject.removerObserver(observer1); 21 | subject.notifyObserver(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Observer/src/main/java/me/lishuo/interf/impl/CountObserver.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.interf.impl; 2 | 3 | import me.lishuo.interf.Observer; 4 | import me.lishuo.interf.Subject; 5 | 6 | /** 7 | * Created by lis on 17/3/12. 8 | */ 9 | public class CountObserver implements Observer { 10 | 11 | @Override 12 | public void update(Subject subject) { 13 | for (int i = 5; i > 0; i--){ 14 | System.out.println("CountObserver is working. i = " + i); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Observer/src/main/java/me/lishuo/interf/impl/CountObserver1.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.interf.impl; 2 | 3 | import me.lishuo.interf.Observer; 4 | import me.lishuo.interf.Subject; 5 | 6 | /** 7 | * Created by lis on 17/3/12. 8 | */ 9 | public class CountObserver1 implements Observer { 10 | 11 | @Override 12 | public void update(Subject subject) { 13 | for (int i = 5; i > 0; i--){ 14 | System.out.println("CountObserver1 is working. i = " + i); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Observer/src/main/java/me/lishuo/interf/impl/CountSubject.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.interf.impl; 2 | 3 | import me.lishuo.interf.Observer; 4 | import me.lishuo.interf.Subject; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by lis on 17/3/12. 11 | */ 12 | public class CountSubject implements Subject { 13 | 14 | private List observerList; 15 | 16 | public CountSubject() { 17 | observerList = new ArrayList<>(); 18 | } 19 | 20 | public void registerObserver(Observer observer) { 21 | observerList.add(observer); 22 | } 23 | 24 | public void removerObserver(Observer observer) { 25 | observerList.remove(observer); 26 | } 27 | 28 | public void notifyObserver() { 29 | observerList.stream().forEach(o -> o.update(this)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### Java设计模式实现与总结 2 | 3 | ------- 4 | 5 | 本项目将陆续整理有关Java设计模式的实现与总结。目前已整理: 6 | 7 | ##### 创建型模式 8 | * [单例模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Singleton) 9 | * [简单工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/SimpleFactory) 10 | * [抽象工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/AbstractFactory) 11 | 12 | ##### 行为型模式 13 | * [观察者模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Observer) 14 | * [模板方法模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/TemplateMethod) 15 | 16 | ##### 结构型模式 17 | 18 | * [适配器模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Adapter) 19 | 20 | -------------------------------------------------------------------------------- /SimpleFactory/README.md: -------------------------------------------------------------------------------- 1 | #### JAVA设计模式系列: 2 | * [单例模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Singleton) 3 | * [观察者模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Observer) 4 | * [模板方法模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/TemplateMethod) 5 | * [简单工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/SimpleFactory) 6 | * [抽象工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/AbstractFactory) 7 | * [适配器模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Adapter) 8 | 9 | # 简单工厂模式 10 | 11 | ### 定义 12 | 简单工厂模式又叫做静态工厂方法模式,是常用的实例化对象模式。 13 | ### 角色 14 | 15 | * **工厂类**:工厂类包含了负责创建所有实例具体逻辑;可以直接被外界调用来创建所需要的对象。 16 | * **抽象产品类**:工厂类所创建对象的父类。 17 | 18 | * **具体产品类**:工厂类创建的具体对象。 19 | 20 | ### 实现 21 | 这里简单写一个示例来实现普通工厂模式。 22 | #### 类图 23 | ![](https://ww3.sinaimg.cn/large/006tKfTcgy1fe3w4e3wsfj30v70c2t9n.jpg) 24 | #### 抽象产品类 25 | 26 | ```java 27 | public interface IFruit { 28 | 29 | void get(); 30 | } 31 | ``` 32 | 定义了一个抽象水果类`IFruit`,其中包含一个`get()`。 33 | 34 | #### 具体产品类 35 | 36 | ```java 37 | public class Apple implements IFruit { 38 | 39 | @Override 40 | public void get() { 41 | System.out.println("I am a apple."); 42 | } 43 | } 44 | 45 | public class Orange implements IFruit { 46 | 47 | @Override 48 | public void get() { 49 | System.out.println("I am a orange." ); 50 | } 51 | } 52 | ``` 53 | 定义了2个具体水果类`Apple`、`Orange`分别实现了`IFruit`的`get()`方法。 54 | 55 | #### 工厂类 56 | ```java 57 | public class FruitFactory { 58 | 59 | public static IFruit getFruit(String type) { 60 | 61 | IFruit ifruit = null; 62 | if ("apple".equals(type)) { 63 | ifruit = new Apple(); 64 | } else if ("orange".equals(type)) { 65 | ifruit = new Orange(); 66 | } 67 | return ifruit; 68 | } 69 | } 70 | ``` 71 | 工厂类包含一个静态方法`getFruit()`,功能是:根据不同的`type`返回不同的水果实例。 72 | #### 测试 73 | 74 | ```java 75 | public static void main(String[] args) { 76 | 77 | IFruit apple = FruitFactory.getFruit("apple"); 78 | IFruit orange = FruitFactory.getFruit("orange"); 79 | 80 | apple.get(); 81 | orange.get(); 82 | } 83 | ``` 84 | 85 | 分别调用水果工厂`FruitFactory`类来实例化2个不同的水果实例。运行结果: 86 | ``` 87 | I am a apple. 88 | I am a orange. 89 | ``` 90 | 91 | #### 总结 92 | * 优点:可以隐藏具体类名称,提供参数给使用者直接调用;避免直接实例化对象,无需准备构造函数参数。 93 | 94 | * 缺点:在增加新产品的时候,必须修改工厂类,违背了开放封闭原则。 95 | 96 | 97 | -------------------------------------------------------------------------------- /SimpleFactory/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | JavaDesignPattern 7 | me.lishuo 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | SimpleFactory 13 | 14 | 15 | -------------------------------------------------------------------------------- /SimpleFactory/src/main/java/me/lishuo/FruitFactory.java: -------------------------------------------------------------------------------- 1 | package me.lishuo; 2 | 3 | import me.lishuo.impl.Apple; 4 | import me.lishuo.impl.Orange; 5 | import me.lishuo.interf.IFruit; 6 | 7 | /** 8 | * Created by lis on 17/3/29. 9 | */ 10 | public class FruitFactory { 11 | 12 | public static IFruit getFruit(String type) { 13 | 14 | IFruit ifruit = null; 15 | if ("apple".equals(type)) { 16 | ifruit = new Apple(); 17 | } else if ("orange".equals(type)) { 18 | ifruit = new Orange(); 19 | } 20 | return ifruit; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SimpleFactory/src/main/java/me/lishuo/Test.java: -------------------------------------------------------------------------------- 1 | package me.lishuo; 2 | 3 | import me.lishuo.interf.IFruit; 4 | 5 | /** 6 | * Created by lis on 17/3/29. 7 | */ 8 | public class Test { 9 | 10 | public static void main(String[] args) { 11 | 12 | IFruit apple = FruitFactory.getFruit("apple"); 13 | IFruit orange = FruitFactory.getFruit("orange"); 14 | 15 | apple.get(); 16 | orange.get(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SimpleFactory/src/main/java/me/lishuo/impl/Apple.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.impl; 2 | 3 | import me.lishuo.interf.IFruit; 4 | 5 | /** 6 | * Created by lis on 17/3/29. 7 | */ 8 | public class Apple implements IFruit { 9 | 10 | @Override 11 | public void get() { 12 | System.out.println("I am a apple."); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /SimpleFactory/src/main/java/me/lishuo/impl/Orange.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.impl; 2 | 3 | import me.lishuo.interf.IFruit; 4 | 5 | /** 6 | * Created by lis on 17/3/29. 7 | */ 8 | public class Orange implements IFruit { 9 | 10 | @Override 11 | public void get() { 12 | System.out.println("I am a orange." ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /SimpleFactory/src/main/java/me/lishuo/interf/IFruit.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.interf; 2 | 3 | /** 4 | * Created by lis on 17/3/29. 5 | */ 6 | public interface IFruit { 7 | 8 | void get(); 9 | } 10 | -------------------------------------------------------------------------------- /Singleton/README.md: -------------------------------------------------------------------------------- 1 | #### JAVA设计模式系列: 2 | * [单例模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Singleton) 3 | * [观察者模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Observer) 4 | * [模板方法模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/TemplateMethod) 5 | * [简单工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/SimpleFactory) 6 | * [抽象工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/AbstractFactory) 7 | * [适配器模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Adapter) 8 | 9 | ## 单例模式 10 | 11 | 通常Java实现单例模式有很多种方式,大致可分为`懒汉模式`和`饿汉模式`,其主要区别是实例延迟加载的问题,当然单例模式往往也关注其他问题,如:线程安全等。下面试图来总结单例模式的这些注意点。 12 | 13 | 14 | ### 饿汉模式 15 | 16 | ```java 17 | public class Singleton { 18 | private Singleton(){} 19 | private static Singleton instance = new Singleton(); 20 | 21 | public static Singleton getInstance() { 22 | return instance; 23 | } 24 | } 25 | ``` 26 | 饿汉模式在类加载时候就实例化对象,使用时直接调用`getInstance()`方法。这个模式下,是线程安全的,在多线程并发模式下不会重复实例化对象。 27 | **缺点:对象过早的实例化,浪费系统资源。** 28 | 29 | ### 懒汉模式 30 | ```java 31 | 32 | public class Singleton { 33 | private Singleton(){} 34 | private static Singleton instance = null; 35 | public static Singleton getInstance() { 36 | if (instance == null) { 37 | instance = new Singleton(); 38 | } 39 | return instance; 40 | } 41 | } 42 | ``` 43 | 这种模式下在类加载时候并没有实例化对象,而是在调用`getInstance()`方法。之所以使用懒汉模式,是为了避免多早的实例化对象,从而浪费系统资源。 44 | **缺点:仅适用于单线程,线程不安全。** 45 | #### 改进1 - 引入`synchronized` 46 | ```java 47 | public class Singleton { 48 | private Singleton(){} 49 | private static Singleton instance = null; 50 | 51 | public static synchronized Singleton getInstance() { 52 | if (instance == null) { 53 | instance = new Singleton(); 54 | } 55 | return instance; 56 | } 57 | } 58 | ``` 59 | 之所以引入`synchronized`修饰`getInstance()`方法,是为了解决线程不安全的问题。利用多线程同步机制,让原先的线程不安全回归到线程安全。但引入`synchronized`会因为线程阻塞、切换会带一些不必要的开销,从而降低系统性能。 60 | #### 改进2 - 双重检查锁定 61 | ```java 62 | public class Singleton { 63 | private Singleton(){} 64 | private static volatile Singleton instance = null; 65 | 66 | public static Singleton getInstance() { 67 | if (instance == null) { // A 68 | synchronized (Singleton.class) { 69 | if (instance == null) { // B 70 | instance = new Singleton(); // C 71 | } 72 | } 73 | } 74 | return instance; 75 | } 76 | } 77 | ``` 78 | 对比改进1中,可以看到`synchronized`不再修饰一个方法,而是缩减到修改代码块,因为加锁同步的话,范围越小,性能影响最小。 79 | 80 | 这里可以注意到修饰变量`instance`的关键字增加了`volatile`。这里`volatile`主要作用是提供内存屏障,禁止指令重排序。 81 | > 现有t1、t2两个线程同时访问`getInstance()`,假设t1、t2都执行到A处。由于有同步锁,只能有个1个线程获得锁,假如t1拥有该同步锁,t1执行到C处`instace = new Singleton()`。将会做如下3步骤: 82 | > 1.分配内存空间 83 | 2.初始化 84 | 3.将instance指向分配内存空间 85 | 正常的执行顺序应为:1->2->3。执行第3步时,这时候的`instance`就不再是null了。但由于指令重排序的存在,执行顺序有可能变化为:1->3->2。当执行3的时候,`instance`就不再是null,但初始化工作有可能还没有做完。这时候如果t2获取锁执行的话,就会直接获取有可能还没有初始化完成的`instance`。这样使用`instance`会引起程序报错。当然这也是极端情况下,我尝试几次无法捕捉重现,但并不意味着问题不存在。`volatile`当然还是要加的。 86 | 87 | **A**处`if`判断作用主要是防止过多是线程执行同步代码块;如果是单例模式的话,这里同步代码块只会被执行一次。**B**处`if`判断作用主要是防止多线程作用下重复实例化,保证线程安全。这也被称为:**双重检查锁定**。 88 | 89 | 双重检查锁定属于一种兼顾线程安全和性能的实现。 90 | 91 | 92 | #### 改进3 - 静态内部类 93 | ```java 94 | public class Singleton { 95 | private Singleton(){} 96 | private static class Holder { 97 | public static Singleton instance = new Singleton(); 98 | } 99 | 100 | public static Singleton getInstance() { 101 | return Holder.instance; // 执行Holder的初始化工作 102 | } 103 | } 104 | 105 | ``` 106 | 使用静态内部类也是懒汉模式的一种实现,当调用`getInstance()`才会触发加载静态内部类,从而初始化获取`instance`实例。利用静态内部类的加载机制来保证线程安全。 107 | 108 | 109 | ### 枚举方式 110 | 111 | ```java 112 | 113 | public enum Singleton { 114 | INSTANCE; 115 | Singleton(){} 116 | 117 | public Singleton getInstance() { 118 | return INSTANCE; 119 | } 120 | } 121 | 122 | ``` 123 | 用枚举方式实现单例模式,是目前比较推荐的。枚举方式的好处是:1、线程安全;2、防止反射出现多个实例;3、防止反序列化出现多个实例。 124 | 125 | 126 | 127 | **以上是关于Java单例模式的一些总结,如有纰漏,还请指出。** 128 | 129 | -------------------------------------------------------------------------------- /Singleton/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | JavaDesignPattern 7 | me.lishuo 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | Singleton 13 | 14 | 15 | -------------------------------------------------------------------------------- /Singleton/src/main/java/me/lishuo/sample/Singleton.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.sample; 2 | 3 | /** 4 | * 懒汉模式,线程不安全,适用于单线程 5 | * Created by lis on 17/3/10. 6 | */ 7 | public class Singleton { 8 | 9 | private static Singleton instance = null; 10 | 11 | public static Singleton getInstance() { 12 | if (instance == null) { 13 | instance = new Singleton(); 14 | } 15 | return instance; 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Singleton/src/main/java/me/lishuo/sample/Singleton1.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.sample; 2 | 3 | /** 4 | * 懒汉模式改进,线程安全 5 | * Created by lis on 17/3/10. 6 | */ 7 | public class Singleton1 { 8 | 9 | private static Singleton1 instance = null; 10 | 11 | private Singleton1() { 12 | } 13 | 14 | /** 15 | * 新增synchronized关键字,利用同步机制使得该实现下适用于多线程环境 16 | * 17 | * @return 18 | */ 19 | public static synchronized Singleton1 getInstance() { 20 | if (instance == null) { 21 | instance = new Singleton1(); 22 | } 23 | return instance; 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Singleton/src/main/java/me/lishuo/sample/Singleton2.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.sample; 2 | 3 | /** 4 | * 懒汉模式改进,线程安全 5 | * Created by lis on 17/3/10. 6 | */ 7 | public class Singleton2 { 8 | 9 | private static volatile Singleton2 instance = null; 10 | 11 | private Singleton2() { 12 | } 13 | /** 14 | * 双重检查锁定,线程安全兼顾效率 15 | * 16 | * @return 17 | */ 18 | public static Singleton2 getInstance() { 19 | if (instance == null) { 20 | synchronized (Singleton2.class) { 21 | if (instance == null) { 22 | instance = new Singleton2(); 23 | } 24 | 25 | } 26 | } 27 | return instance; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Singleton/src/main/java/me/lishuo/sample/Singleton3.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.sample; 2 | 3 | /** 4 | * 基于内部类方式的单例模式,线程安全 5 | * Created by lis on 17/3/10. 6 | */ 7 | public class Singleton3 { 8 | 9 | private Singleton3() { 10 | } 11 | 12 | private static class Holder { 13 | public static Singleton3 instance = new Singleton3(); 14 | } 15 | 16 | public static Singleton3 getInstance() { 17 | return Holder.instance; // 执行Holder的初始化工作 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Singleton/src/main/java/me/lishuo/sample/Singleton4.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.sample; 2 | 3 | /** 4 | * 饿汉模式,线程安全 5 | * Created by lis on 17/3/10. 6 | */ 7 | public class Singleton4 { 8 | private static Singleton4 instance = new Singleton4(); 9 | 10 | private Singleton4() { 11 | } 12 | 13 | public static Singleton4 getInstance() { 14 | return instance; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Singleton/src/main/java/me/lishuo/sample/Singleton5.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.sample; 2 | 3 | /** 4 | * 通过枚举实现单例模式 5 | * Created by lis on 17/3/10. 6 | */ 7 | public enum Singleton5 { 8 | INSTANCE; 9 | 10 | Singleton5() { 11 | } 12 | 13 | public Singleton5 getInstance() { 14 | return INSTANCE; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Singleton/src/main/java/me/lishuo/sample/TestSingleton.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.sample; 2 | 3 | /** 4 | * Created by lis on 17/3/10. 5 | */ 6 | public class TestSingleton implements Runnable { 7 | 8 | public void run() { 9 | 10 | Singleton2 singleton2 = Singleton2.getInstance(); 11 | System.out.println(singleton2.hashCode()); 12 | 13 | } 14 | 15 | public static void main(String[] args) { 16 | 17 | Thread[] threads = new Thread[10]; 18 | for (int i = 0; i < 10; i++) { 19 | threads[i] = new Thread(new TestSingleton()); 20 | threads[i].start(); 21 | } 22 | 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TemplateMethod/README.md: -------------------------------------------------------------------------------- 1 | #### JAVA设计模式系列: 2 | * [单例模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Singleton) 3 | * [观察者模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Observer) 4 | * [模板方法模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/TemplateMethod) 5 | * [简单工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/SimpleFactory) 6 | * [抽象工厂模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/AbstractFactory) 7 | * [适配器模式](https://github.com/lishuo9527/JavaDesignPatterns/tree/master/Adapter) 8 | 9 | # 模板方法模式 10 | ### 定义 11 | 模板方法模式在一个方法中定义了算法的骨架,把其中的某些步骤延迟到子类的实现,是为我们提供了代码复用的一种重要的技巧。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。 12 | 13 | ### 实现 14 | 这里简单通过一个示例来展示到底什么时候模板方法模式。这个示例向我们展示了制作咖啡和茶2种咖啡因饮料的过程,在这个过程中展示了模板方法模式的具体使用方法。 15 | 先看一下模板方法模式的类图: 16 | 17 | ![](https://ww2.sinaimg.cn/large/006tNc79gy1fdr54brd65j30sd0kkwg6.jpg) 18 | 19 | 20 | 首先我们定义一个抽象类`CaffeineBeverage`来作为模板方法的基类。具体代码如下: 21 | 22 | ```java 23 | public abstract class CaffeineBeverage { 24 | 25 | // 模板方法 26 | final void prepareReipe() { 27 | boilWater(); 28 | brew(); 29 | pourInCup(); 30 | addCondiments(); 31 | } 32 | 33 | // 浸泡 34 | abstract void brew(); 35 | 36 | // 加料 37 | abstract void addCondiments(); 38 | 39 | // 煮水 40 | void boilWater() { 41 | System.out.println("Boiling water"); 42 | } 43 | 44 | // 倒进杯子里 45 | void pourInCup() { 46 | System.out.println("Pouring into cup"); 47 | } 48 | ``` 49 | 在`CaffeineBeverage`类中定义了一个名为`prepareReipe()`的模板方法,用来描述冲泡咖啡因饮料的过程。方法用`final`修饰是为了防止子类修改方法的执行顺序。 50 | 51 | `CaffeineBeverage`类定义了4个方法,分别是`brew()`、`addCondiments()`、`boilWater()`、`pourInCup()`。在我们的示例中,冲泡咖啡和茶共有的过程分别是`煮水 boilWater()`、`倒进杯子里 pourInCup()`。这两个共用方法选择在`CaffeineBeverage`类实现。 52 | 53 | `Tea`类、`Coffee`类是`CaffeineBeverage`类的子类。而`加料 addCondiments()`、`浸泡 brew()`分别在`Tea`类、`Coffee`类中有各自不同的实现。如下所示: 54 | 55 | ```java 56 | public class Tea extends CaffeineBeverage { 57 | 58 | void brew() { 59 | System.out.println("Stepping the tea."); 60 | } 61 | 62 | void addCondiments() { 63 | System.out.println("Adding Lemon"); 64 | } 65 | } 66 | ``` 67 | ```java 68 | public class Coffee extends CaffeineBeverage { 69 | 70 | void brew() { 71 | System.out.println("Dripping Coffee through filter"); 72 | } 73 | 74 | void addCondiments() { 75 | System.out.println("Adding Suger and Mike"); 76 | } 77 | } 78 | ``` 79 | 完成了模板方法模式的代码,我们可以进行测试一下,测试类: 80 | 81 | ```java 82 | public class Test { 83 | 84 | public static void main(String[] args) { 85 | Tea tea = new Tea(); 86 | tea.prepareReipe(); 87 | 88 | System.out.println("**************"); 89 | 90 | Coffee coffee = new Coffee(); 91 | coffee.prepareReipe(); 92 | } 93 | } 94 | ``` 95 | 输出结果: 96 | 97 | ``` 98 | Boiling water 99 | Stepping the tea. 100 | Pouring into cup 101 | Adding Lemon 102 | ************** 103 | Boiling water 104 | Dripping Coffee through filter 105 | Pouring into cup 106 | Adding Suger and Mike 107 | ``` 108 | 我们将冲茶和咖啡重复的方法`煮水 boilWater()`、`倒进杯子里 pourInCup()`抽象出来,每个子类分别去实现各自特有的步骤。以上便是模板方法的实例。 109 | 110 | #### 钩子 111 | 还需了解到,模板方法模式还有`钩子`的概念。`钩子`是一种被声明在抽象类的方法,可以为空或者默认的实现。`钩子`的存在可以让子类有能力对算法的不同点进行挂钩,是否需要挂钩由子类决定。 112 | 113 | 借助上面的示例来展示`钩子`如何使用。首先我们在抽象类`CaffeineBeverage`定一个钩子,钩子的默认实现返回`true`。如下: 114 | 115 | ``` 116 | // 定义一个钩子 117 | boolean customerWantsCondiments() { 118 | return true; 119 | } 120 | ``` 121 | 并修改模板方法: 122 | 123 | ```java 124 | // 模板方法 125 | final void prepareReipe() { 126 | boilWater(); 127 | brew(); 128 | pourInCup(); 129 | if (customerWantsCondiments()) { 130 | addCondiments(); 131 | } 132 | } 133 | ``` 134 | 目的是增加让客户选择是否需要给茶或者饮料来添加东西。我们可以在子类中覆盖`钩子`的写法。这里改下下`Tea`类,如下: 135 | 136 | ```java 137 | public class Tea extends CaffeineBeverage { 138 | 139 | private String msg; 140 | 141 | public Tea(String msg) { 142 | this.msg = msg; 143 | } 144 | 145 | void brew() { 146 | System.out.println("Stepping the tea."); 147 | } 148 | 149 | void addCondiments() { 150 | System.out.println("Adding Lemon"); 151 | } 152 | 153 | boolean customerWantsCondiments() { 154 | if ("y".equals(this.msg)) { 155 | return true; 156 | } else { 157 | return false; 158 | } 159 | } 160 | } 161 | ``` 162 | 添加了一个`msg`变量,可以通过构造函数进行赋值,当`msg`为`y`时候,我们将在茶里添加柠檬,否则不添加。看一下测试代码: 163 | 164 | ```java 165 | public static void main(String[] args) { 166 | Tea tea = new Tea("n"); 167 | tea.prepareReipe(); 168 | 169 | System.out.println("**************"); 170 | 171 | Coffee coffee = new Coffee(); 172 | coffee.prepareReipe(); 173 | } 174 | ``` 175 | 运行结果: 176 | 177 | ``` 178 | Boiling water 179 | Stepping the tea. 180 | Pouring into cup 181 | ************** 182 | Boiling water 183 | Dripping Coffee through filter 184 | Pouring into cup 185 | Adding Suger and Mike 186 | ``` 187 | 和上面的比较一下,发现制作茶的过程中缺少了添加东西的过程,主要是因为我们在`Tea`类,重写了钩子,来控制加料的步骤。 188 | 189 | 190 | 如有纰漏,烦请指出。 191 | 192 | **参考《Head First 设计模式》** 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /TemplateMethod/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | JavaDesignPattern 7 | me.lishuo 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | TemplateMethod 13 | 14 | 15 | -------------------------------------------------------------------------------- /TemplateMethod/src/main/java/me/lishuo/templatemethod/CaffeineBeverage.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.templatemethod; 2 | 3 | /** 4 | * Created by lis on 17/3/18. 5 | */ 6 | public abstract class CaffeineBeverage { 7 | 8 | // 模板方法 9 | final void prepareReipe() { 10 | boilWater(); 11 | brew(); 12 | pourInCup(); 13 | if (customerWantsCondiments()) { 14 | addCondiments(); 15 | } 16 | } 17 | 18 | // 浸泡 19 | abstract void brew(); 20 | 21 | // 加料 22 | abstract void addCondiments(); 23 | 24 | // 煮水 25 | void boilWater() { 26 | System.out.println("Boiling water"); 27 | } 28 | 29 | // 倒进杯子里 30 | void pourInCup() { 31 | System.out.println("Pouring into cup"); 32 | } 33 | 34 | // 定义一个钩子 35 | boolean customerWantsCondiments() { 36 | return true; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TemplateMethod/src/main/java/me/lishuo/templatemethod/Coffee.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.templatemethod; 2 | 3 | /** 4 | * Created by lis on 17/3/18. 5 | */ 6 | public class Coffee extends CaffeineBeverage { 7 | 8 | void brew() { 9 | System.out.println("Dripping Coffee through filter"); 10 | } 11 | 12 | void addCondiments() { 13 | System.out.println("Adding Suger and Mike"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TemplateMethod/src/main/java/me/lishuo/templatemethod/Tea.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.templatemethod; 2 | 3 | /** 4 | * Created by lis on 17/3/18. 5 | */ 6 | public class Tea extends CaffeineBeverage { 7 | 8 | private String msg; 9 | 10 | public Tea(String msg) { 11 | this.msg = msg; 12 | } 13 | 14 | void brew() { 15 | System.out.println("Stepping the tea."); 16 | } 17 | 18 | void addCondiments() { 19 | System.out.println("Adding Lemon"); 20 | } 21 | 22 | boolean customerWantsCondiments() { 23 | if ("y".equals(this.msg)) { 24 | return true; 25 | } else { 26 | return false; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /TemplateMethod/src/main/java/me/lishuo/templatemethod/Test.java: -------------------------------------------------------------------------------- 1 | package me.lishuo.templatemethod; 2 | 3 | /** 4 | * Created by lis on 17/3/18. 5 | */ 6 | public class Test { 7 | 8 | public static void main(String[] args) { 9 | Tea tea = new Tea("n"); 10 | tea.prepareReipe(); 11 | 12 | System.out.println("**************"); 13 | 14 | Coffee coffee = new Coffee(); 15 | coffee.prepareReipe(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.lishuo 8 | JavaDesignPattern 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | Singleton 13 | Observer 14 | TemplateMethod 15 | SimpleFactory 16 | SimpleFactory 17 | AbstractFactory 18 | Adapter 19 | 20 | 21 | 22 | --------------------------------------------------------------------------------