設計模式筆記——GoF設計模式彙總

目錄

· 總述php

    · 記憶css

    · 效果java

    · 面向對象設計原則ios

· 建立型模式正則表達式

    · 單例模式(Singleton)算法

        · 效果數據庫

        · 分類編程

        · 代碼(餓漢式)設計模式

        · 代碼(懶漢式)安全

        · 代碼(雙重檢測鎖式)

        · 代碼(靜態內部類式)

        · 代碼(枚舉單例)

        · 代碼(使用反射的破解與防護)

        · 代碼(使用序列化的破解與防護)

        · 應用場景

    · 工廠模式

        · 效果

        · 分類

        · 代碼(簡單工廠)

        · 代碼(工廠方法)

        · 代碼(抽象工廠)

        · 應用場景

    · 構建者模式(Builder)

        · 效果

        · 代碼

        · 應用場景

    · 原型模式(Prototype)

        · 效果

        · 核心角色

        · 代碼(淺克隆)

        · 代碼(基於JDK的深克隆)

        · 代碼(基於序列化的深克隆)

        · 應用場景

· 結構型模式

    · 適配器模式(Adapter)

        · 效果

        · 核心角色

        · 分類

        · 代碼(使用繼承)

        · 代碼(使用關聯)

        · 應用場景

    · 代理模式(Proxy)

        · 效果

        · 核心角色

        · 分類

        · 代碼(靜態代理)

        · 代碼(動態代理)

        · 應用場景

    · 橋接模式(Bridge)

        · 效果

        · 代碼

        · 應用場景

    · 組合模式(Composite)

        · 效果

        · 核心角色

        · 代碼

        · 代碼(殺毒舉例)

        · 應用場景

    · 裝飾器模式(Decorator)

        · 效果

        · 核心角色

        · 代碼

        · 應用場景

    · 外觀模式(Facade)

        · 效果

        · 代碼

        · 應用場景

    · 享元模式(FlyWeight)

        · 效果

        · 核心角色

        · 代碼

        · 應用場景

· 行爲型模式

    · 責任鏈模式(Chain of Resposibility)

        · 效果

        · 核心角色

        · 代碼

        · 應用場景

    · 迭代器模式(Iterator)

        · 效果

        · 核心角色

        · 代碼

        · 應用場景

    · 中介者模式(Mediator)

        · 效果

        · 代碼

        · 應用場景

    · 命令模式(Command)

        · 效果

        · 核心角色

        · 代碼

        · 應用場景

    · 解釋器模式(Interpreter)

        · 效果

        · 應用場景

    · 訪問者模式(Visitor)

        · 效果

        · 應用場景

    · 策略模式(Strategy)

        · 效果

        · 代碼

        · 應用場景

    · 模板方法模式(Template Method)

        · 效果

        · 代碼

        · 應用場景

    · 狀態模式(State)

        · 效果

        · 核心角色

        · 代碼

        · 應用場景

    · 觀察者模式(Observer)

        · 效果

        · 代碼

        · 代碼(基於JDK)

        · 應用場景

    · 備忘錄模式(Memento)

        · 效果

        · 核心角色

        · 代碼

        · 應用場景


 

總述

記憶

1. 建立型:sbfp;

2. 結構型:abcdffp;

3. 行爲型:iimmccsstov。

效果

1. 全部面向對象設計原則和設計模式都是爲了下降代碼耦合度,提升擴展性、複用,手段是「分工」。

2. 相似社會分工,現代社會比原始社會發展得大,也是由於分工。

面向對象設計原則 

首字母

代指

解釋

S

單一功能原則(Single Responsibility Principle)

對象應該僅具備一種單一功能。

O

開閉原則(Open/Closed Principle)

軟件體應該是對於擴展開放的,可是對於修改封閉的。

L

里氏替換原則(Liskov Substitution Principle)

程序中的對象應該是能夠在不改變程序正確性的前提下被它的子類所替換的。

I

接口隔離原則(Interface Segregation Principle)

多個特定客戶端接口要好於一個寬泛用途的接口。

D

依賴反轉原則(Dependency Inversion Principle)

一個方法應該聽從依賴於抽象而不是一個實例

建立型模式

單例模式(Singleton)

效果

1. 保證一個類只有一個實例,而且提供一個訪問該實例的全局訪問點。

2. 因爲單例模式只生成一個實例,減小了系統性能開銷,當一個對象的產生須要比較多的資源時,如讀取配置、產生其餘依賴對象時,則能夠經過在應用啓動時直接產生一個單例對象,而後永久駐留內存的方式來解決。

分類

1. 常見實現方式。

    a) 餓漢式:線程安全,調用效率高,不能延時加載。

    b) 懶漢式:線程安全,調用效率不高,可延時加載。

2. 其餘實現方式。

    a) 雙重檢測鎖式:因爲JVM底層內部模型緣由,偶爾出問題,不建議使用。

    b) 靜態內部類式:線程安全,調用效率高,可延時加載。

    c) 枚舉單例:線程安全,調用效率高,不能延時加載。

3. 選擇方法。

    a) 單例對象佔用資源少,不須要延時加載:枚舉式好於餓漢式;

    b) 單例對象佔用資源多,須要延時加載:靜態內部類好於懶漢式。

代碼(餓漢式)

1. Singleton.java

 1 public class Singleton {
 2 
 3     // 類初始化時當即建立對象
 4     private static final Singleton instance = new Singleton();
 5     
 6     // 私有化構造器
 7     private Singleton() {
 8         if (instance != null) {
 9             throw new RuntimeException();
10         }
11     }
12     
13     public static Singleton getInstance() {
14         return instance;
15     }
16     
17 }
View Code

2. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         Singleton singleton1 = Singleton.getInstance();
5         Singleton singleton2 = Singleton.getInstance();
6         System.out.println(singleton1 == singleton2);
7     }
8 
9 }
View Code

代碼(懶漢式)

1. Singleton.java

 1 public class Singleton {
 2 
 3     private static Singleton instance;
 4     
 5     // 私有化構造器
 6     private Singleton() {
 7     }
 8     
 9     // 同步方法
10     public static synchronized Singleton getInstance() {
11         if (instance == null) {
12             // 延時加載
13             instance = new Singleton();
14         }
15         return instance;
16     }
17     
18 }
View Code

2. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         Singleton singleton1 = Singleton.getInstance();
5         Singleton singleton2 = Singleton.getInstance();
6         System.out.println(singleton1 == singleton2);
7     }
8 
9 }
View Code

代碼(雙重檢測鎖式)

1. Singleton.java

 1 public class Singleton {
 2 
 3     private static volatile Singleton instance;
 4     
 5     // 私有化構造器
 6     private Singleton() {
 7     }
 8     
 9     public static Singleton getInstance() {
10         if (instance == null) {
11             // 第一次建立時同步
12             synchronized (Singleton.class) {
13                 if (instance == null) {
14                     // 延時加載
15                     instance = new Singleton();
16                 }
17             }
18         }
19         return instance;
20     }
21     
22 }
View Code

2. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         Singleton singleton1 = Singleton.getInstance();
5         Singleton singleton2 = Singleton.getInstance();
6         System.out.println(singleton1 == singleton2);
7     }
8 
9 }
View Code

代碼(靜態內部類式)

1. Singleton.java

 1 public class Singleton {
 2     
 3     // 初始化外部類時不會當即初始化內部類
 4     private static class SingletonInstance {
 5         private static final Singleton instance = new Singleton();
 6     }
 7 
 8     // 私有化構造器
 9     private Singleton() {
10     }
11     
12     public static Singleton getInstance() {
13         return SingletonInstance.instance;
14     }
15     
16 }
View Code

2. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         Singleton singleton1 = Singleton.getInstance();
5         Singleton singleton2 = Singleton.getInstance();
6         System.out.println(singleton1 == singleton2);
7     }
8 
9 }
View Code

代碼(枚舉單例)

1. Singleton.java

 1 public enum Singleton {
 2     
 3     // 枚舉自己就是單例
 4     INSTANCE;
 5     
 6     // 添加須要的方法
 7     public void method() {
 8     }
 9     
10 }
View Code

2. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         Singleton singleton1 = Singleton.INSTANCE;
5         Singleton singleton2 = Singleton.INSTANCE;
6         System.out.println(singleton1 == singleton2);
7     }
8 
9 }
View Code

代碼(使用反射的破解與防護)

1. Singleton.java

 1 public class Singleton {
 2 
 3     // 類初始化時當即建立對象
 4     private static final Singleton instance = new Singleton();
 5     
 6     // 私有化構造器
 7     private Singleton() {
 8         // 防護:再次建立時拋出異常
 9         if (instance != null) {
10             throw new RuntimeException();
11         }
12     }
13     
14     public static Singleton getInstance() {
15         return instance;
16     }
17     
18 }
View Code

2. Client.java

 1 import java.lang.reflect.Constructor;
 2 
 3 public class Client {
 4 
 5     public static void main(String[] args) throws Exception {
 6         Singleton singleton1 = Singleton.getInstance();
 7         
 8         Class<Singleton> clazz = Singleton.class;
 9         Constructor<Singleton> constructor = clazz.getDeclaredConstructor();
10         constructor.setAccessible(true);
11         Singleton singleton2 = constructor.newInstance();
12         System.out.println(singleton1 == singleton2);
13     }
14 
15 }
View Code

代碼(使用序列化的破解與防護)

1. Singleton.java

 1 import java.io.Serializable;
 2 
 3 public class Singleton implements Serializable {
 4 
 5     private static final long serialVersionUID = -3230831923851678463L;
 6     
 7     // 類初始化時當即建立對象
 8     private static final Singleton instance = new Singleton();
 9     
10     // 私有化構造器
11     private Singleton() {
12     }
13     
14     public static Singleton getInstance() {
15         return instance;
16     }
17     
18     // 防護:反序列化時,直接返回該方法的返回值
19     private Object readResolve() {
20         return instance;
21     }
22     
23 }
View Code

2. Client.java

 1 import java.io.File;
 2 import java.io.FileInputStream;
 3 import java.io.FileOutputStream;
 4 import java.io.ObjectInputStream;
 5 import java.io.ObjectOutputStream;
 6 
 7 public class Client {
 8 
 9     public static void main(String[] args) throws Exception {
10         Singleton singleton1 = Singleton.getInstance();
11         
12         File tempFile = new File("D:/test");
13         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(tempFile));
14         oos.writeObject(singleton1);
15         oos.close();
16         ObjectInputStream ios = new ObjectInputStream(new FileInputStream(tempFile));
17         Singleton singleton2 = (Singleton) ios.readObject();
18         ios.close();
19         System.out.println(singleton1 == singleton2);
20         
21     }
22 
23 }
View Code

應用場景

1. Windows的Task Manager(任務管理器)。

2. Windows的Recycle Bin(回收站)。

3. 項目中,讀取配置文件的類,通常只有一個對象,不必每次建立。

4. 數據庫鏈接池。

5. Application是單例的典型應用(Servlet編程)。

6. Spring中,每一個Bean默認是單例的。

7. 每一個Servlet是單例。

8. Spring MVC中,控制器對象是單例的。

工廠模式

效果

1. 實例化對象,用工廠方法代替new。實現了建立者和調用者的分離。

2. 將選擇實現類、建立對象統一管理和控制,從而將調用者跟咱們的實現類解耦。

分類

1. 簡單工廠模式:用來產生同一等級結構中的任意產品。對於增長新的產品,須要修改已有代碼。

2. 工廠方法模式:用來產生同一等級結構中的固定產品。支持增長任意產品。

3. 抽象工廠模式:用來生產不一樣產品族的所有產品。對於增長新的產品,無能爲力;支持增長產品族。

4. 簡單工廠模式效果:

    a) 又稱靜態工廠模式。

    b) 工廠類通常使用靜態方法,經過接收的參數來返回不一樣的對象實例。

    c) 對於增長新產品只能修改代碼(違反OCP)。

    d) 有兩種實現方式(見代碼)。

5. 工廠方法模式效果:

    a) 避免簡單工廠的缺點,但不徹底知足OCP。

    b) 簡單工廠模式VS.工廠方法模式:

        i. 結構複雜度:顯然簡單工廠模式佔優,簡單工廠模式只要一個工廠,而工廠方法模式的工廠類隨着產品類個數增長而增長。

        ii. 代碼複雜度:代碼複雜度與結構複雜度相反,簡單工廠模式的工廠類隨着產品增長鬚要增長更多方法(代碼),而工廠方法模式每一個具體工廠類只完成單一任務,代碼簡單。

        iii. 客戶端編程難度:工廠方法模式雖然知足了OCP,但客戶端編碼中須要對工廠實例化,而簡單工廠模式的工廠類是一個靜態類。

        iv. 管理上的難度:工廠方法模式須要維護的工廠類過多,而簡單工廠模式只有一個。

    c) 設計理論建議使用工廠方法模式,但實際中通常都用簡單工廠模式。

6. 抽象工廠模式效果:

    a) 用來生產不一樣產品族的所有產品。對於增長新的產品,無能爲力;支持增長產品族。

    b) 抽象工廠模式是工廠方法模式的升級版本,在有多個業務品種、業務分類時,經過抽象工廠模式產生須要的對象時一種很是好的解決方式。

代碼(簡單工廠)

1. Car.java

1 public interface Car {
2 
3     void run();
4     
5 }
View Code

2. Audi.java

1 public class Audi implements Car {
2 
3     @Override
4     public void run() {
5         System.out.println("奧迪在跑!");
6     }
7 
8 }
View Code

3. Byd.java

1 public class Byd implements Car {
2 
3     @Override
4     public void run() {
5         System.out.println("比亞迪在跑!");
6     }
7 
8 }
View Code

4. CarFactory.java

 1 // 一個方法實現
 2 public class CarFactory1 {
 3 
 4     public static Car createCar(String type) {
 5         if ("Audi".equals(type)) {
 6             return new Audi();
 7         }
 8         if ("Byd".equals(type)) {
 9             return new Byd();
10         }
11         return null;
12     }
13     
14 }
View Code

5. CarFactory2.java

 1 // 多個方法實現
 2 public class CarFactory2 {
 3     
 4     public static Car createAudi() {
 5         return new Audi();
 6     }
 7 
 8     public static Car createByd() {
 9         return new Byd();
10     }
11     
12 }
View Code

6. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         Car car1 = CarFactory1.createCar("Audi");
 5         Car car2 = CarFactory1.createCar("Byd");
 6         car1.run();
 7         car2.run();
 8     }
 9 
10 }
View Code

代碼(工廠方法)

1. Car.java

1 public interface Car {
2 
3     void run();
4     
5 }
View Code

2. CarFactory.java

1 public interface CarFactory {
2 
3     Car createCar();
4     
5 }
View Code

3. Audi.java

1 public class Audi implements Car {
2 
3     @Override
4     public void run() {
5         System.out.println("奧迪在跑!");
6     }
7 
8 }
View Code

4. AudiFactory.java

1 public class AudiFactory implements CarFactory {
2 
3     @Override
4     public Car createCar() {
5         return new Audi();
6     }
7 
8 }
View Code

5. Byd.java

1 public class Byd implements Car {
2 
3     @Override
4     public void run() {
5         System.out.println("比亞迪在跑!");
6     }
7 
8 }
View Code

6. BydFactory.java

1 public class BydFactory implements CarFactory {
2 
3     @Override
4     public Car createCar() {
5         return new Byd();
6     }
7 
8 }
View Code

7. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         Car car1 = new AudiFactory().createCar();
 5         Car car2 = new BydFactory().createCar();
 6         car1.run();
 7         car2.run();
 8     }
 9 
10 }
View Code

代碼(抽象工廠)

1. Engine.java

 1 public interface Engine {
 2 
 3     void start();
 4     
 5     void speedUp();
 6     
 7 }
 8 
 9 class LuxuryEngine implements Engine {
10     
11     @Override
12     public void start() {
13         System.out.println("快速啓動!");
14     }
15     
16     @Override
17     public void speedUp() {
18         System.out.println("快速加速!");
19     }
20     
21 }
22 
23 class LowEngine implements Engine {
24 
25     @Override
26     public void start() {
27         System.out.println("慢速啓動!");
28     }
29 
30     @Override
31     public void speedUp() {
32         System.out.println("慢速加速!");
33     }
34     
35 }
View Code

2. Seat.java

 1 public interface Seat {
 2 
 3     void massage();
 4     
 5 }
 6 
 7 class LuxurySeat implements Seat {
 8     
 9     @Override
10     public void massage() {
11         System.out.println("按摩!");
12     }
13     
14 }
15 
16 class LowSeat implements Seat {
17 
18     @Override
19     public void massage() {
20         System.out.println("不能按摩!");
21     }
22     
23 }
View Code

3. Tire.java

 1 public interface Tire {
 2 
 3     void revolve();
 4     
 5 }
 6 
 7 class LuxuryTire implements Tire {
 8 
 9     @Override
10     public void revolve() {
11         System.out.println("旋轉不磨損!");
12     }
13     
14 }
15 
16 class LowTire implements Tire {
17 
18     @Override
19     public void revolve() {
20         System.out.println("旋轉磨損快!");
21     }
22     
23 }
View Code

4. CarFactory.java

 1 public interface CarFactory {
 2 
 3     Engine createEngine();
 4     
 5     Seat createSeat();
 6     
 7     Tire createTire();
 8     
 9 }
10 
11 class LuxuryCarFactory implements CarFactory {
12     
13     @Override
14     public Engine createEngine() {
15         return new LuxuryEngine();
16     }
17     
18     @Override
19     public Seat createSeat() {
20         return new LuxurySeat();
21     }
22     
23     @Override
24     public Tire createTire() {
25         return new LuxuryTire();
26     }
27     
28 }
29 
30 class LowCarFactory implements CarFactory {
31 
32     @Override
33     public Engine createEngine() {
34         return new LowEngine();
35     }
36 
37     @Override
38     public Seat createSeat() {
39         return new LowSeat();
40     }
41 
42     @Override
43     public Tire createTire() {
44         return new LowTire();
45     }
46     
47 }
View Code

5. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         CarFactory carFactory = new LuxuryCarFactory();
 5         Engine engine = carFactory.createEngine();
 6         engine.start();
 7         engine.speedUp();
 8     }
 9 
10 }
View Code

應用場景

1. JDK中Calendar.getInstance()方法。

2. JDBC中Connection對象的獲取。

3. Hibernate中SessionFactory建立Session。

4. Spring中IoC容器建立管理Bean對象。

5. 反射中Class對象的newInstance()方法。

構建者模式(Builder)

效果

1. 構建一個複雜的產品(如神舟飛船、iPhone)時,須要解決「如何裝配子組件」的問題。

2. 分離了對象子組件的單獨構建(Builder)和裝配(Director),從而構造出複雜對象。

3. 因爲實現了構建和裝配的解耦。不一樣的構建器、相同的裝配,或者相同的構建器、不一樣的裝配,均可以建立不一樣的對象。

4. 建造者模式通常與工廠模式搭配,由工廠模式建立子組件,再有建造者模式裝配。

代碼

1. Airship.java

 1 public class Airship {
 2 
 3     private Engine engine;
 4     
 5     private OrbitalModule orbitalModule;
 6     
 7     private EscapeTower escapeTower;
 8     
 9     public void launch() {
10         System.out.println(engine.getName() + "點火!");
11         System.out.println(orbitalModule.getName() + "發射!");
12     }
13 
14     public Engine getEngine() {
15         return engine;
16     }
17 
18     public void setEngine(Engine engine) {
19         this.engine = engine;
20     }
21 
22     public OrbitalModule getOrbitalModule() {
23         return orbitalModule;
24     }
25 
26     public void setOrbitalModule(OrbitalModule orbitalModule) {
27         this.orbitalModule = orbitalModule;
28     }
29 
30     public EscapeTower getEscapeTower() {
31         return escapeTower;
32     }
33 
34     public void setEscapeTower(EscapeTower escapeTower) {
35         this.escapeTower = escapeTower;
36     }
37     
38 }
39 
40 class Engine {
41     
42     private String name;
43     
44     public String getName() {
45         return name;
46     }
47     
48     public void setName(String name) {
49         this.name = name;
50     }
51     
52 }
53 
54 class OrbitalModule {
55     
56     private String name;
57     
58     public String getName() {
59         return name;
60     }
61     
62     public void setName(String name) {
63         this.name = name;
64     }
65     
66 }
67 
68 class EscapeTower {
69     
70     private String name;
71 
72     public String getName() {
73         return name;
74     }
75 
76     public void setName(String name) {
77         this.name = name;
78     }
79     
80 }
View Code

2. AirshipBuilder.java

1 public interface AirshipBuilder {
2 
3     Engine buildEngine();
4     
5     OrbitalModule buildOrbitalModule();
6     
7     EscapeTower buildEscapeTower();
8     
9 }
View Code

3. AirshipDirector.java

1 public interface AirshipDirector {
2 
3     Airship directAirship();
4     
5 }
View Code

4. SzAirshipBuilder.java

 1 public class SzAirshipBuilder implements AirshipBuilder {
 2 
 3     @Override
 4     public Engine buildEngine() {
 5         // 也可以使用工廠模式建立
 6         Engine engine = new Engine();
 7         engine.setName("神舟發動機");
 8         return engine;
 9     }
10 
11     @Override
12     public OrbitalModule buildOrbitalModule() {
13         // 也可以使用工廠模式建立
14         OrbitalModule orbitalModule = new OrbitalModule();
15         orbitalModule.setName("神舟軌道艙");
16         return orbitalModule;
17     }
18 
19     @Override
20     public EscapeTower buildEscapeTower() {
21         // 也可以使用工廠模式建立
22         EscapeTower escapeTower = new EscapeTower();
23         escapeTower.setName("神舟逃逸塔");
24         return escapeTower;
25     }
26 
27 }
View Code

5. SzAirshipDirector.java

 1 public class SzAirshipDirector implements AirshipDirector {
 2 
 3     private AirshipBuilder airshipBuilder;
 4     
 5     public SzAirshipDirector(AirshipBuilder airshipBuilder) {
 6         this.airshipBuilder = airshipBuilder;
 7     }
 8 
 9     @Override
10     public Airship directAirship() {
11         Engine engine = airshipBuilder.buildEngine();
12         OrbitalModule orbitalModule = airshipBuilder.buildOrbitalModule();
13         EscapeTower escapeTower = airshipBuilder.buildEscapeTower();
14         
15         Airship airship = new Airship();
16         airship.setEngine(engine);
17         airship.setOrbitalModule(orbitalModule);
18         airship.setEscapeTower(escapeTower);
19         
20         return airship;
21     }
22 
23 }
View Code

6. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         AirshipDirector airshipDirector = new SzAirshipDirector(new SzAirshipBuilder());
5         Airship airship = airshipDirector.directAirship();
6         airship.launch();
7     }
8     
9 }
View Code

應用場景

1. StringBuilder.append()方法。

2. SQL中的PareparedStatement。

原型模式(Prototype)

效果

1. 經過new建立對象須要很是繁瑣的數據準備或訪問權限,則可使用原型模式。

2. 就是Java中的克隆技術,以某個對象爲原型,複製出新的對象。

3. 優點:效率高,避免從新執行構建過程。

4. 克隆相似於new,但不一樣於new。new建立新的對象屬性採用默認值。克隆出的對象屬性徹底與原型對象相同,而且克隆出的新對象改變不會影響原型對象,而後再修改克隆對象的值。

核心角色

1. Clonable接口的clone()方法。

2. 實現原型模式最困難的是內存複製操做,所幸Java提供了clone()方法。

代碼(淺克隆)

1. Sheep.java

 1 import java.util.Date;
 2 
 3 public class Sheep implements Cloneable {
 4 
 5     private String name;
 6     
 7     private Date birthday;
 8     
 9     @Override
10     protected Object clone() throws CloneNotSupportedException {
11         return super.clone();
12     }
13 
14     public String getName() {
15         return name;
16     }
17 
18     public void setName(String name) {
19         this.name = name;
20     }
21 
22     public Date getBirthday() {
23         return birthday;
24     }
25 
26     public void setBirthday(Date birthday) {
27         this.birthday = birthday;
28     }
29     
30 }
View Code

2. Client.java

 1 import java.util.Date;
 2 
 3 public class Client {
 4 
 5     public static void main(String[] args) throws Exception {
 6         Sheep sheep1 = new Sheep();
 7         sheep1.setName("少利");
 8         sheep1.setBirthday(new Date());
 9         
10         Sheep sheep2 = (Sheep) sheep1.clone();
11         sheep2.setName("多利");
12         System.out.println(sheep2.getName());
13         System.out.println(sheep2.getBirthday());
14         
15         // 淺克隆
16         System.out.println(sheep1.getBirthday() == sheep2.getBirthday());
17     }
18 
19 }
View Code

代碼(基於JDK的深克隆)

1. Sheep.java

 1 import java.util.Date;
 2 
 3 public class Sheep implements Cloneable {
 4 
 5     private String name;
 6     
 7     private Date birthday;
 8     
 9     @Override
10     protected Object clone() throws CloneNotSupportedException {
11         Sheep sheep = (Sheep) super.clone();
12         sheep.setBirthday((Date) birthday.clone());
13         return sheep;
14     }
15 
16     public String getName() {
17         return name;
18     }
19 
20     public void setName(String name) {
21         this.name = name;
22     }
23 
24     public Date getBirthday() {
25         return birthday;
26     }
27 
28     public void setBirthday(Date birthday) {
29         this.birthday = birthday;
30     }
31     
32 }
View Code

2. Client.java

 1 import java.util.Date;
 2 
 3 public class Client {
 4 
 5     public static void main(String[] args) throws Exception {
 6         Sheep sheep1 = new Sheep();
 7         sheep1.setName("少利");
 8         sheep1.setBirthday(new Date());
 9         
10         Sheep sheep2 = (Sheep) sheep1.clone();
11         sheep2.setName("多利");
12         System.out.println(sheep2.getName());
13         System.out.println(sheep2.getBirthday());
14         
15         // 深克隆
16         System.out.println(sheep1.getBirthday() == sheep2.getBirthday());
17     }
18 
19 }
View Code

代碼(基於序列化的深克隆)

1. Sheep.java

 1 import java.io.ByteArrayInputStream;
 2 import java.io.ByteArrayOutputStream;
 3 import java.io.IOException;
 4 import java.io.ObjectInputStream;
 5 import java.io.ObjectOutputStream;
 6 import java.io.Serializable;
 7 import java.util.Date;
 8 
 9 public class Sheep implements Cloneable, Serializable {
10 
11     private static final long serialVersionUID = 2155997264135266066L;
12 
13     private String name;
14     
15     private Date birthday;
16     
17     @Override
18     protected Object clone() throws CloneNotSupportedException {
19         Sheep sheep = null;
20         ByteArrayOutputStream baos = null;
21         ObjectOutputStream oos = null;
22         ByteArrayInputStream bais = null;
23         ObjectInputStream ois = null;
24         try {
25             baos = new ByteArrayOutputStream();
26             oos = new ObjectOutputStream(baos);
27             oos.writeObject(this);
28             byte[] bytes = baos.toByteArray();
29             bais = new ByteArrayInputStream(bytes);
30             ois = new ObjectInputStream(bais);
31             sheep = (Sheep) ois.readObject();
32             
33         } catch (IOException | ClassNotFoundException e) {
34             e.printStackTrace();
35         }
36         return sheep;
37     }
38 
39     public String getName() {
40         return name;
41     }
42 
43     public void setName(String name) {
44         this.name = name;
45     }
46 
47     public Date getBirthday() {
48         return birthday;
49     }
50 
51     public void setBirthday(Date birthday) {
52         this.birthday = birthday;
53     }
54     
55 }
View Code

2. Client.java

 1 import java.util.Date;
 2 
 3 public class Client {
 4 
 5     public static void main(String[] args) throws Exception {
 6         Sheep sheep1 = new Sheep();
 7         sheep1.setName("少利");
 8         sheep1.setBirthday(new Date());
 9         
10         Sheep sheep2 = (Sheep) sheep1.clone();
11         sheep2.setName("多利");
12         System.out.println(sheep2.getName());
13         System.out.println(sheep2.getBirthday());
14         
15         // 深克隆
16         System.out.println(sheep1.getBirthday() == sheep2.getBirthday());
17     }
18 
19 }
View Code

應用場景

1. 原型模式不多單獨使用,通常與工廠模式一塊兒出現。經過clone()方法建立對象後由工廠模式返回。

2. Spring的Bean建立有單例模式和原型模式兩種方式。

結構型模式

適配器模式(Adapter)

效果

將一個類的接口轉換成客戶但願的另外一個接口,使本來因爲接口不兼容而不能一塊兒工做的那些類能夠在一塊兒工做。

核心角色

1. 目標接口(Target):客戶所指望的接口(接口、抽象類或具體類)。

2. 適配的類(Adaptee)。

3. 適配器(Adapter):經過包裝適配的類,把原接口轉換成目標接口。

分類

1. 使用繼承實現:Adapter繼承Adaptee。

2. 使用關聯實現:Adapter持有Adaptee的引用,Adapter能夠繼承其餘類,更靈活。

代碼(使用繼承)

1. Target.java

1 public interface Target {
2 
3     void handleRequest();
4     
5 }
View Code

2. Adaptee.java

1 public class Adaptee {
2 
3     public void request() {
4         System.out.println("處理請求!");
5     }
6     
7 }
View Code

3. Adapter.java

1 public class Adapter extends Adaptee implements Target {
2     
3     @Override
4     public void handleRequest() {
5         request();
6     }
7 
8 }
View Code

4. Client.java

 1 public class Client {
 2     
 3     public void execute(Target target) {
 4         target.handleRequest();
 5     }
 6 
 7     public static void main(String[] args) {
 8         Target target = new Adapter();
 9         new Client().execute(target);
10     }
11 
12 }
View Code

代碼(使用關聯)

1. Target.java

1 public interface Target {
2 
3     void handleRequest();
4     
5 }
View Code

2. Adaptee.java

1 public class Adaptee {
2 
3     public void request() {
4         System.out.println("處理請求!");
5     }
6     
7 }
View Code

3. Adapter.java

 1 public class Adapter implements Target {
 2     
 3     // 使用關聯更靈活,這樣適配器能夠繼承其餘類
 4     private Adaptee adaptee;
 5 
 6     public Adapter(Adaptee adaptee) {
 7         this.adaptee = adaptee;
 8     }
 9 
10     @Override
11     public void handleRequest() {
12         adaptee.request();
13     }
14 
15 }
View Code

4. Client.java

 1 public class Client {
 2     
 3     public void execute(Target target) {
 4         target.handleRequest();
 5     }
 6 
 7     public static void main(String[] args) {
 8         Target target = new Adapter();
 9         new Client().execute(target);
10     }
11 
12 }
View Code

應用場景

1. 作舊系統改造和升級。

2. java.io.InputStreamReader(InputStream)。

3. java.io.OutputStreamWriter(OutputStream)。

代理模式(Proxy)

效果

1. 經過代理,控制對對象的訪問。

2. 能夠詳細控制訪問某個(某類)對象的方法,在調用方法前作前置處理,調用方法後作後置處理(即APO的微觀實現)。

3. AOP(Aspect Oriented Programming,面向切面編程)的核心實現機制。

核心角色

1. 抽象角色:定義代理角色和真實角色的公共對外方法。

2. 真實角色:實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色調用。

3. 代理角色:實現抽象角色,是真實角色的代理,經過真實角色的業務邏輯方法來實現抽象方法,並能夠附加本身操做。

分類

1. 靜態代理(靜態定義代理類)。

2. 動態代理(動態定義代理類):

    a) JDK自帶的動態代理(java.lang.reflect.Proxy動態生成代理類和對象,java.lang.reflect.InvocationHandler經過invoke()方法實現訪問真實角色);

    b) javaassist字節碼操做庫實現;

    c) CGLIB;

    d) ASM(底層使用指令,可維護性較差)。

代碼(靜態代理)

1. Star.java

 1 public interface Star {
 2 
 3     void confer();
 4     
 5     void signContract();
 6     
 7     void bookTicket();
 8     
 9     void sing();
10     
11     void collectMoney();
12     
13 }
View Code

2. RealStar.java

 1 public class RealStar implements Star {
 2 
 3     @Override
 4     public void confer() {
 5         System.out.println("RealStar.confer()");
 6     }
 7 
 8     @Override
 9     public void signContract() {
10         System.out.println("RealStar.signContract()");
11     }
12 
13     @Override
14     public void bookTicket() {
15         System.out.println("RealStar.bookTicket()");
16     }
17 
18     @Override
19     public void sing() {
20         System.out.println("RealStar.sing()");
21     }
22 
23     @Override
24     public void collectMoney() {
25         System.out.println("RealStar.collectMoney()");
26     }
27 
28 }
View Code

3. ProxyStar.java

 1 public class ProxyStar implements Star {
 2     
 3     private Star realStar;
 4     
 5     public ProxyStar(Star realStar) {
 6         this.realStar = realStar;
 7     }
 8 
 9     @Override
10     public void confer() {
11         System.out.println("ProxyStar.confer()");
12     }
13 
14     @Override
15     public void signContract() {
16         System.out.println("ProxyStar.signContract()");
17     }
18 
19     @Override
20     public void bookTicket() {
21         System.out.println("ProxyStar.bookTicket()");
22     }
23 
24     @Override
25     public void sing() {
26         realStar.sing();
27     }
28 
29     @Override
30     public void collectMoney() {
31         System.out.println("ProxyStar.collectMoney()");
32     }
33 
34 }
View Code

4. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         RealStar realStar = new RealStar();
 5         ProxyStar proxyStar = new ProxyStar(realStar);
 6         proxyStar.confer();
 7         proxyStar.signContract();
 8         proxyStar.bookTicket();
 9         proxyStar.sing();
10         proxyStar.collectMoney();
11     }
12 
13 }
View Code

代碼(動態代理)

1. Star.java

 1 public interface Star {
 2 
 3     void confer();
 4     
 5     void signContract();
 6     
 7     void bookTicket();
 8     
 9     void sing();
10     
11     void collectMoney();
12     
13 }
View Code

2. RealStar.java

 1 public class RealStar implements Star {
 2 
 3     @Override
 4     public void confer() {
 5         System.out.println("RealStar.confer()");
 6     }
 7 
 8     @Override
 9     public void signContract() {
10         System.out.println("RealStar.signContract()");
11     }
12 
13     @Override
14     public void bookTicket() {
15         System.out.println("RealStar.bookTicket()");
16     }
17 
18     @Override
19     public void sing() {
20         System.out.println("RealStar.sing()");
21     }
22 
23     @Override
24     public void collectMoney() {
25         System.out.println("RealStar.collectMoney()");
26     }
27 
28 }
View Code

3. StarHandler.java

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 
 4 public class StarHandler implements InvocationHandler {
 5     
 6     private Star realStar;
 7 
 8     public StarHandler(Star realStar) {
 9         this.realStar = realStar;
10     }
11 
12     @Override
13     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
14         switch (method.getName()) {
15         case "confer":
16             System.out.println("ProxyStar.confer()");
17             break;
18         case "signContract":
19             System.out.println("ProxyStar.signContract()");
20             break;
21         case "bookTicket":
22             System.out.println("ProxyStar.bookTicket()");
23             break;
24         case "sing":
25             method.invoke(realStar, args);
26             break;
27         case "collectMoney":
28             System.out.println("ProxyStar.collectMoney()");
29             break;
30         }
31         
32         return null;
33     }
34 
35 }
View Code

4. Client.java

 1 import java.lang.reflect.Proxy;
 2 
 3 public class Client {
 4 
 5     public static void main(String[] args) {
 6         Star realStar = new RealStar();
 7         StarHandler handler = new StarHandler(realStar);
 8         Star proxyStar = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] { Star.class }, handler);
 9         proxyStar.confer();
10         proxyStar.signContract();
11         proxyStar.bookTicket();
12         proxyStar.sing();
13         proxyStar.collectMoney();
14     }
15 
16 }
View Code

應用場景

1. 安全代理:屏蔽對真實角色的直接訪問。

2. 遠程代理:經過代理類處理遠程方法調用(RMI)。

3. 延遲代理:先加載輕量級代理對象,真正須要時再加載真實對象。

橋接模式(Bridge)

效果

1. 處理多層繼承結構、處理多維變化的場景,將各個維度設計成獨立的繼承結構,使各個維度能夠獨立的擴展在抽象層創建關聯。

2. 以商場系統中的電腦分類爲例,多層繼承不利於擴展性(類個數膨脹問題):

    a) 若是要增長一個新的電腦類型智能手機,則要增長各個品牌下面的類。

    b) 若是要增長一個新的品牌,也要增長各類電腦類型的類。

3. 違反單一職責原則:好比一個聯想筆記本,有兩個引發這個類變化的緣由。

4. 橋接模式將電腦拆分爲類型和品牌兩個維度。

代碼

1. Computer.java

 1 public abstract class Computer {
 2 
 3     protected Brand brand;
 4 
 5     public Computer(Brand brand) {
 6         this.brand = brand;
 7     }
 8     
 9     public abstract void run();
10     
11 }
12 
13 class Desktop extends Computer {
14 
15     public Desktop(Brand brand) {
16         super(brand);
17     }
18 
19     @Override
20     public void run() {
21         System.out.println(brand.getName() + "臺式機運行!");
22     }
23     
24 }
25 
26 class Laptop extends Computer {
27 
28     public Laptop(Brand brand) {
29         super(brand);
30     }
31 
32     @Override
33     public void run() {
34         System.out.println(brand.getName() + "筆記本運行!");
35     }
36     
37 }
View Code

2. Brand.java

 1 public interface Brand {
 2 
 3     String getName();
 4     
 5 }
 6 
 7 class Lenovo implements Brand {
 8     
 9     @Override
10     public String getName() {
11         return "聯想";
12     }
13     
14 }
15 
16 class Dell implements Brand {
17 
18     @Override
19     public String getName() {
20         return "戴爾";
21     }
22     
23 }
View Code

3. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         Brand brand = new Lenovo();
5         Computer computer = new Laptop(brand);
6         computer.run();
7     }
8 
9 }
View Code

應用場景

1. JDBC驅動程序。

2. 銀行日誌管理。

    a) 格式分類:操做日誌、交易日誌、異常日誌。

    b) 距離分類:本地記錄日誌、異地記錄日誌。

3. 人力資源系統的獎金計算模塊。

    a) 獎金分類:我的獎金、團體獎金、激勵獎金。

    b) 部門分類:人事部門、銷售部門、研發部門。

4. OA系統的消息處理。

    a) 業務類型:普通消息、加急消息、特急消息。

    b) 發送消息方式:系統內消息、手機短信、郵件。

組合模式(Composite)

效果

1. 把部分和整理的關係用樹形結構表示,從而使客戶端可使用統一方式處理部分對象和總體對象。

2. 組合模式爲處理樹形結構提供了完美的解決方案,描述瞭如何將容器和葉子進行遞歸組合,使得用戶在使用時能夠一致性的對待容器和葉子。

核心角色

1. 抽象構件角色(Component):定義了葉子和容器構件的共同點。

2. 葉子構件角色(Leaf):無子節點。

3. 容器構件角色(Composite):有容器特徵,能夠包含子節點。

代碼

Component.java

 1 import java.util.List;
 2 
 3 public interface Component {
 4 
 5     void operation();
 6     
 7 }
 8 
 9 interface Leaf extends Component {
10     
11 }
12 
13 interface Composite extends Component {
14     
15     void add(Component child);
16     
17     void remove(Component child);
18     
19     List<Component> getChildren();
20     
21 }
View Code

代碼(殺毒舉例)

1. AbstractFile.java

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public interface AbstractFile {
 5 
 6     void killVirus();
 7     
 8 }
 9 
10 class File implements AbstractFile {
11     
12     private String name;
13 
14     public File(String name) {
15         this.name = name;
16     }
17 
18     @Override
19     public void killVirus() {
20         System.out.println(name + " 文件殺毒!");
21     }
22     
23 }
24 
25 class Folder implements AbstractFile {
26     
27     private String name;
28     private List<AbstractFile> children = new ArrayList<>();
29 
30     public Folder(String name) {
31         this.name = name;
32     }
33     
34     public void add(AbstractFile child) {
35         children.add(child);
36     }
37     
38     public void remove(AbstractFile child) {
39         children.remove(child);
40     }
41 
42     @Override
43     public void killVirus() {
44         for (AbstractFile child : children) {
45             child.killVirus();
46         }
47         System.out.println(name + " 文件夾殺毒!");
48     }
49     
50 }
View Code

2. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         Folder myDocument = new Folder("個人文檔");
 5         myDocument.add(new File("Client.java"));
 6         myDocument.add(new File("index.php"));
 7         myDocument.add(new File("老師.avi"));
 8         Folder book = new Folder("圖書");
 9         book.add(new File("設計模式.pdf"));
10         book.add(new File("Hadoop權威指南.pdf"));
11         myDocument.add(book);
12         myDocument.killVirus();
13     }
14 
15 }
View Code

應用場景

1. 操做系統的資源管理器。

2. GUI的容器層次圖。

3. XML文件解析。

4. OA系統的組織結構處理。

5. JUnit單元測試框架:Test接口(抽象)、TestCase(葉子)、TestUnit(容器)。

裝飾器模式(Decorator)

效果

1. 又稱包裝器模式(Wrapper)。

2. 動態的爲一個對象增長新的功能。

3. 裝飾器模式是一種用於代替繼承的技術,無須經過繼承增長子類就能擴展對象的新功能。使用對象的關聯關係代替繼承關係,更加靈活,同時避免類型體系的快速膨脹。

4. 裝飾器模式下降系統的耦合度,能夠動態的增長或刪除對象的職責,並使得須要裝飾的具體構件類和具體裝飾類能夠獨立變化,以便增長新的具體構件類和具體裝飾類。

核心角色

1. 抽象構件角色(Component):具體構件角色和裝飾角色有相同的接口,客戶端可以以與具體構件角色相同的方式同裝飾角色交互。

2. 具體構件角色(ConcreteComponent)。

3. 裝飾角色(Decorator):持有一個抽象構件角色引用,接收全部客戶端請求,並把這些請求轉發給具體裝飾角色。

4. 具體裝飾角色(ConcreteDecorator):給構件增長新功能。

代碼

1. ICar.java

 1 public interface ICar {
 2 
 3     void move();
 4     
 5 }
 6 
 7 // 具體構建角色
 8 class Car implements ICar {
 9 
10     @Override
11     public void move() {
12         System.out.println("陸地上跑!");
13     }
14     
15 }
16 
17 // 裝飾器角色
18 abstract class SuperCar implements ICar {
19 
20     private ICar car;
21     
22     public SuperCar(ICar car) {
23         this.car = car;
24     }
25 
26     public abstract void move();
27     
28 }
29 
30 class FlyCar extends SuperCar {
31 
32     public FlyCar(ICar car) {
33         super(car);
34     }
35     
36     @Override
37     public void move() {
38         super.move();
39         fly();
40     }
41     
42     public void fly() {
43         System.out.println("天上飛!");
44     }
45     
46 }
47 
48 class WaterCar extends SuperCar {
49     
50     public WaterCar(ICar car) {
51         super(car);
52     }
53 
54     @Override
55     public void move() {
56         super.move();
57         swim();
58     }
59     
60     public void swim() {
61         System.out.println("水上游!");
62     }
63     
64 }
65 
66 class AICar extends SuperCar {
67 
68     public AICar(ICar car) {
69         super(car);
70     }
71 
72     @Override
73     public void move() {
74         super.move();
75         autoMove();
76     }
77     
78     public void autoMove() {
79         System.out.println("自動跑!");
80     }
81     
82 }
View Code

2. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         Car car = new Car();
 5         car.move();
 6         
 7         // 陸地上跑 + 天上飛
 8         FlyCar flyCar = new FlyCar(car);
 9         flyCar.move();
10         
11         // 陸地上跑  + 水上游
12         WaterCar waterCar = new WaterCar(car);
13         waterCar.move();
14         
15         // 陸地上跑  + 自動跑
16         AICar aiCar = new AICar(car);
17         aiCar.move();
18         
19         // 陸地上跑 + 天上飛 + 水上游
20         WaterCar flyWaterCar = new WaterCar(flyCar);
21         flyWaterCar.move();
22         
23         // 陸地上跑 + 天上飛 + 水上游 + 自動跑
24         AICar aiFlyWaterCar = new AICar(flyWaterCar);
25         aiFlyWaterCar.move();
26     }
27 
28 }
View Code

應用場景

1. IO的InputStream、OutputStream、Reader、Writer的設計。

2. Servlet API的request對象的默認實現類HttpServletRequestWrapper。

外觀模式(Facade)

效果

1. 爲子系統提供統一的入口。封裝子系統的複雜性,便於客戶端調用。

2. 迪米特法則:一個軟件實體應當儘量少地與其餘實體發生相互做用。

代碼

1. Tea.java

1 public interface Tea {
2 
3     String getName();
4     
5     void drink();
6     
7 }
View Code

2. WaitressFacade.java

  1 public class WaitressFacade {
  2 
  3     public Tea makeTea(String teaName) {
  4         Water water = new Water("農夫山泉", 100.0);
  5         Tea tea = null;
  6         switch (teaName) {
  7         case "西湖龍井":
  8             tea = new XiHuLongJing();
  9             break;
 10         case "碧螺春":
 11             tea = new BiLuoChun();
 12             break;
 13         case "鐵觀音":
 14             tea = new TieGuanYin();
 15             break;
 16         default:
 17             return null;
 18         }
 19         TeaSet teaSet = new TeaSet();
 20         teaSet.cleanTeaSet(water);
 21         teaSet.addTea(tea);
 22         teaSet.cleanTea(water);
 23         teaSet.makeTea(water);
 24         return tea;
 25     }
 26     
 27 }
 28 
 29 class Water {
 30     
 31     private String name;
 32     
 33     private Double temperature;
 34 
 35     public Water(String name, Double temperature) {
 36         this.name = name;
 37         this.temperature = temperature;
 38     }
 39 
 40     public String getName() {
 41         return name;
 42     }
 43 
 44     public Double getTemperature() {
 45         return temperature;
 46     }
 47 
 48 }
 49 
 50 class TeaSet {
 51     
 52     private Tea tea;
 53     
 54     public void cleanTeaSet(Water water) {
 55         System.out.println("使用" + water.getTemperature() + "°的" + water.getName() + "燙洗茶具!");
 56     }
 57     
 58     public void addTea(Tea tea) {
 59         System.out.println("投入" + tea.getName() + "!");
 60         this.tea = tea;
 61     }
 62     
 63     public void cleanTea(Water water) {
 64         System.out.println("使用" + water.getTemperature() + "°的" + water.getName() + "洗茶!");
 65     }
 66     
 67     public Tea makeTea(Water water) {
 68         System.out.println("使用" + water.getTemperature() + "°的" + water.getName() + "泡茶!");
 69         return tea;
 70     }
 71     
 72 }
 73 
 74 class XiHuLongJing implements Tea {
 75     
 76     @Override
 77     public String getName() {
 78         return "西湖龍井";
 79     }
 80 
 81     @Override
 82     public void drink() {
 83         System.out.println("品" + getName() + "!");
 84     }
 85     
 86 }
 87 
 88 class BiLuoChun implements Tea {
 89     
 90     @Override
 91     public String getName() {
 92         return "洞庭碧螺春";
 93     }
 94     
 95     @Override
 96     public void drink() {
 97         System.out.println("品" + getName() + "!");
 98     }
 99     
100 }
101 
102 class TieGuanYin implements Tea {
103 
104     @Override
105     public String getName() {
106         return "安溪鐵觀音";
107     }
108     
109     @Override
110     public void drink() {
111         System.out.println("品" + getName() + "!");
112     }
113     
114 }
View Code

3. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         WaitressFacade waitressFacade = new WaitressFacade();
5         Tea tea = waitressFacade.makeTea("鐵觀音");
6         tea.drink();
7     }
8 
9 }
View Code

應用場景

1. 頻率很高,到處用到。

2. JDBC封裝後的DbUtils類。

3. Hibernate提供的工具類。

4. Spring JDBC工具類等。

享元模式(FlyWeight)

效果

1. 享元模式以共享的方式高效地支持大量細粒度對象的重用。

    a) 內存屬於稀缺資源,不要隨便浪費。若是有不少個徹底相同或類似的對象,咱們能夠經過享元模式節省內存。

    b) 用時間換取空間。

2. 享元對象能作到共享的關鍵是區分了內部狀態和外部狀態。

    a) 內部狀態:能夠共享,不會隨環境變化而變化。

    b) 外部狀態:不能夠共享,會隨環境變化而變化。

核心角色

1. 享元工廠類(FlyWeightFactory):建立並管理享元對象,享元池通常設計成鍵值對。

2. 抽象享元類(FlyWeight):一般是一個接口或抽象類,聲明公共方法向外界提供對象的內部狀態、設置外部狀態。

3. 具體享元類(ConcreteFlyWeight):爲內部狀態提供成員變量進行存儲。

4. 非共享享元類(UnsharedConcreteFlyWeight):不能被共享的子類能夠設計爲非共享享元類。

代碼

1. ChessFlyWeight.java

1 // 抽象享元類
2 public interface ChessFlyWeight {
3 
4     String getColor();
5     
6     void display(Position position);
7     
8 }
View Code

2. Position.java

 1 // 非共享享元類
 2 public class Position {
 3 
 4     private int x;
 5     
 6     private int y;
 7 
 8     public Position(int x, int y) {
 9         this.x = x;
10         this.y = y;
11     }
12 
13     public int getX() {
14         return x;
15     }
16 
17     public int getY() {
18         return y;
19     }
20 
21 }
View Code

3. ConcreteChess.java

 1 // 具體享元類
 2 public class ConcreteChess implements ChessFlyWeight {
 3     
 4     private String color;
 5 
 6     public ConcreteChess(String color) {
 7         this.color = color;
 8     }
 9     
10     @Override
11     public String getColor() {
12         return color;
13     }
14 
15     @Override
16     public void display(Position position) {
17         System.out.println("顯示:顏色" + color + ",位置(" + position.getX() + "," + position.getY() + ")!");
18     }
19 
20 }
View Code

4. ChessFactory.java

 1 import java.util.HashMap;
 2 import java.util.Map;
 3 
 4 // 享元工廠類
 5 public class ChessFactory {
 6 
 7     private static Map<String, ChessFlyWeight> chesses = new HashMap<>();
 8     
 9     public static ChessFlyWeight getChess(String color) {
10         ChessFlyWeight chess = chesses.get(color);
11         if (chess != null) {
12             return chess;
13         }
14         chess = new ConcreteChess(color);
15         chesses.put(color, chess);
16         return chess;
17     }
18     
19 }
View Code

5. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         ChessFlyWeight chess1 = ChessFactory.getChess("黑");
 5         ChessFlyWeight chess2 = ChessFactory.getChess("黑");
 6         System.out.println(chess1 == chess2);
 7         
 8         chess1.display(new Position(10, 20));
 9         chess1.display(new Position(20, 10));
10     }
11 
12 }
View Code

應用場景

1. 享元模式因爲共享的特性,能夠應用與任何「池」,好比線程池、數據庫鏈接池。

2. String類的設計。

行爲型模式

責任鏈模式(Chain of Resposibility)

效果

1. 將可以處理同一類請求的對象連成一條鏈,所提交的請求沿着鏈傳遞,鏈上的對象逐個判斷是否有能力處理該請求,若是能則處理,不然傳遞給鏈上的下一個對象。

2. 請假條審批過程:天數小於3天,主任審批;大於等於3天,小於10天,經理審批;大於等於10天,小於30天,總經理審批;大於等於30天,拒絕。

核心角色

1. 責任鏈既能夠經過LinkedList實現,也能夠經過ArrayList實現。

2. 可事先定義好責任鏈存儲到配置文件或數據庫。

代碼

1. LeaveRequest.java

 1 public class LeaveRequest {
 2 
 3     private String name;
 4     
 5     private int leaveDays;
 6     
 7     private String reason;
 8 
 9     public LeaveRequest(String name, int leaveDays, String reason) {
10         this.name = name;
11         this.leaveDays = leaveDays;
12         this.reason = reason;
13     }
14 
15     public String getName() {
16         return name;
17     }
18 
19     public int getLeaveDays() {
20         return leaveDays;
21     }
22 
23     public String getReason() {
24         return reason;
25     }
26 
27 }
View Code

2. Leave.java

 1 public abstract class Leader {
 2 
 3     protected String name;
 4     
 5     protected Leader nextLeader;
 6 
 7     public Leader(String name) {
 8         this.name = name;
 9     }
10 
11     public void setNextLeader(Leader nextLeader) {
12         this.nextLeader = nextLeader;
13     }
14     
15     public abstract void handleRequest(LeaveRequest leaveRequest);
16     
17 }
18 
19 class Director extends Leader {
20 
21     public Director(String name) {
22         super(name);
23     }
24 
25     @Override
26     public void handleRequest(LeaveRequest leaveRequest) {
27         if (leaveRequest.getLeaveDays() < 3) {
28             System.out.println("主任" + name + "審批經過!");
29         } else if (nextLeader != null) {
30             nextLeader.handleRequest(leaveRequest);
31         }
32     }
33     
34 }
35 
36 class Manager extends Leader {
37     
38     public Manager(String name) {
39         super(name);
40     }
41     
42     @Override
43     public void handleRequest(LeaveRequest leaveRequest) {
44         if (leaveRequest.getLeaveDays() < 10) {
45             System.out.println("經理" + name + "審批經過!");
46         } else if (nextLeader != null) {
47             nextLeader.handleRequest(leaveRequest);
48         }
49     }
50     
51 }
52 
53 class GeneralManager extends Leader {
54 
55     public GeneralManager(String name) {
56         super(name);
57     }
58 
59     @Override
60     public void handleRequest(LeaveRequest leaveRequest) {
61         if (leaveRequest.getLeaveDays() < 30) {
62             System.out.println("總經理" + name + "審批經過!");
63         } else {
64             System.out.println("不經過!");
65         }
66     }
67     
68 }
View Code

3. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         Leader director = new Director("張三");
 5         Leader manager = new Manager("李四");
 6         Leader generalManager = new GeneralManager("王五");
 7         director.setNextLeader(manager);
 8         manager.setNextLeader(generalManager);
 9         
10         LeaveRequest leaveRequest = new LeaveRequest("Tom", 5, "回英國老家。");
11         director.handleRequest(leaveRequest);
12     }
13 
14 }
View Code

應用場景

1. Java的異常捕獲,try可對應多個catch,當第一個catch不匹配,則自動跳到第二個catch。

2. JavaScript的事件冒泡和捕獲機制。

3. Servlet開發中,過濾器的鏈式處理。

迭代器模式(Iterator)

效果

1. 又稱遊標模式(Cursor)。

2. 提供一種能夠遍歷聚合對象的方式。

核心角色

1. 聚合對象(Aggregate):存儲數據。

2. 迭代器(Iterator):遍歷數據的算法,好比正序、倒序、隨機等。

代碼

1. Iterator.java

1 public interface Iterator {
2 
3     boolean hasNext();
4     
5     Object next();
6     
7 }
View Code

2. Aggregate.java

1 public interface Aggregate {
2 
3     void add(Object element);
4     
5     void remove(Object element);
6     
7     Iterator iterator();
8     
9 }
View Code

3. ConcreteAggregate.java

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public class ConcreteAggregate implements Aggregate {
 5 
 6     private List<Object> list = new ArrayList<>();
 7     
 8     @Override
 9     public void add(Object element) {
10         list.add(element);
11     }
12 
13     @Override
14     public void remove(Object element) {
15         list.remove(element);
16     }
17 
18     @Override
19     public Iterator iterator() {
20         return new ConcreteAggregateIterator();
21     }
22     
23     // 定義成內部類,可直接訪問外部類的屬性
24     private class ConcreteAggregateIterator implements Iterator {
25 
26         private int cursor = -1;
27         
28         @Override
29         public boolean hasNext() {
30             return cursor < list.size() - 1;
31         }
32 
33         @Override
34         public Object next() {
35             cursor++;
36             return list.get(cursor);
37         }
38 
39     }
40 
41 }
View Code

4. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         Aggregate aggregate = new ConcreteAggregate();
 5         aggregate.add("A");
 6         aggregate.add("B");
 7         aggregate.add("C");
 8         aggregate.add("D");
 9         aggregate.add("E");
10         
11         Iterator iterator = aggregate.iterator();
12         while (iterator.hasNext()) {
13             System.out.println(iterator.next());
14         }
15     }
16 
17 }
View Code

應用場景

JDK內置的迭代器。

中介者模式(Mediator)

效果

1. 若是一個系統中對象之間的聯繫呈現爲網狀結構,對象之間存在大量多對多關係,將致使關係及其複雜,這些對象稱爲「同事對象」。

2. 引入一箇中介者對象,使各同事對象只跟中介者對象打交道,將複雜的網狀結構解耦成星狀結構。

3. 解耦多個同事對象之間的交互關係。每一個對象都持有中介者對象的引用,只跟中介者對象打交道。咱們經過中介者對象統一管理這些交互關係。

代碼

1. 公司有總經理,各個部門有事情都通報給總經理,總經理再通知各個相關部門。總經理起到中介、協調做用。

2. Colleague.java

1 public interface Colleague {
2 
3     void selfAction();
4     
5     void outAction();
6     
7 }
View Code

3. Mediator.java

1 public interface Mediator {
2 
3     void register(String name, Colleague colleague);
4     
5     void command(String name);
6     
7 }
View Code

4. DevelopmentDepartment.java

 1 public class DevelopmentDepartment implements Colleague {
 2 
 3     private Mediator mediator;
 4     
 5     public DevelopmentDepartment(Mediator mediator) {
 6         this.mediator = mediator;
 7         mediator.register("研發部", this);
 8     }
 9 
10     @Override
11     public void selfAction() {
12         System.out.println("專心研發!");
13     }
14 
15     @Override
16     public void outAction() {
17         System.out.println("研發部向總經理彙報:須要資金支持!");
18         mediator.command("財務部");
19     }
20 
21 }
View Code

5. MarcketDepartment.java

 1 public class MarcketDepartment implements Colleague {
 2 
 3     private Mediator mediator;
 4     
 5     public MarcketDepartment(Mediator mediator) {
 6         this.mediator = mediator;
 7         mediator.register("市場部", this);
 8     }
 9 
10     @Override
11     public void selfAction() {
12         System.out.println("專心接項目");
13     }
14 
15     @Override
16     public void outAction() {
17         System.out.println("市場部向總經理彙報:須要資金支持!");
18     }
19 
20 }
View Code

6. FinacialDepartment.java

 1 public class FinacialDepartment implements Colleague {
 2 
 3     private Mediator mediator;
 4     
 5     public FinacialDepartment(Mediator mediator) {
 6         this.mediator = mediator;
 7         mediator.register("財務部", this);
 8     }
 9 
10     @Override
11     public void selfAction() {
12         System.out.println("專心數錢!");
13     }
14 
15     @Override
16     public void outAction() {
17         System.out.println("財務部向總經理彙報:錢太多,花不完!");
18         mediator.command("市場部");
19     }
20 
21 }
View Code

7. GeneralManager.java

 1 import java.util.HashMap;
 2 import java.util.Map;
 3 
 4 public class GeneralManager implements Mediator {
 5 
 6     private Map<String, Colleague> colleagues = new HashMap<>();
 7     
 8     @Override
 9     public void register(String name, Colleague colleague) {
10         colleagues.put(name, colleague);
11     }
12 
13     @Override
14     public void command(String name) {
15         colleagues.get(name).outAction();
16     }
17 
18 }
View Code

8. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         Mediator generalManager = new GeneralManager();
 5         Colleague developmentDepartment = new DevelopmentDepartment(generalManager);
 6         Colleague marcketDepartment = new MarcketDepartment(generalManager);
 7         Colleague finacialDepartment = new FinacialDepartment(generalManager);
 8         
 9         developmentDepartment.selfAction();
10         developmentDepartment.outAction();
11     }
12 
13 }
View Code

應用場景

1. MVC模式的C是中介者對象,M和V都和他打交道。

2. GUI中,多個組件之間交互,能夠引入一箇中介者對象(總體窗口對象或DOM對象)。

3. java.lang.reflect.Method#invoke()。

命令模式(Command)

效果

1. 又稱「動做模式(Action)、事務模式(Transaction)。

2. 將一個請求封裝成一個對象,從而使咱們可用不一樣的請求對客戶進行參數化;對請求排隊或者記錄請求日誌,以及支持可撤銷的操做。

核心角色

1. 抽象命令類(Command)。

2. 具體命令類(ConcreteCommand)。

3. 調用者/請求者(Invoker):請求的發送者,經過命令對象來執行請求。調用者並不須要在設計時肯定接收者,而是在運行時,調用命令對象的execute(),間接調用接

收者的相關操做。

4. 接收者(Receiver):執行與請求相關的操做,具體實現對請求的業務處理。

代碼

1. Command.java

1 public interface Command {
2 
3     // 實際中可設計多個方法
4     void execute();
5     
6 }
View Code

2. ConcreteCommand.java

 1 public class ConcreteCommand implements Command {
 2 
 3     private Receiver receiver;
 4     
 5     public ConcreteCommand(Receiver receiver) {
 6         this.receiver = receiver;
 7     }
 8 
 9     @Override
10     public void execute() {
11         // 可在執行先後作其餘操做,好比記錄日誌
12         receiver.action();
13     }
14     
15 }
View Code

3. Invoker.java

 1 public class Invoker {
 2 
 3     // 也能夠是多條命令,相似數據庫事務中的多條命令
 4     private Command command;
 5 
 6     public Invoker(Command command) {
 7         this.command = command;
 8     }
 9     
10     public void call() {
11         command.execute();
12     }
13     
14 }
View Code

4. Receiver.java

1 public class Receiver {
2 
3     public void action() {
4         System.out.println("Receiver.action()");
5     }
6     
7 }
View Code

5. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         Command command = new ConcreteCommand(new Receiver());
5         Invoker invoker = new Invoker(command);
6         invoker.call();
7     }
8 
9 }
View Code

應用場景

數據庫事務機制的底層實現。

解釋器模式(Interpreter)

效果

1. 不經常使用的設計模式。

2. 用於描述如何構成一個簡單的語言解釋器,主要用於使用面嚮對象語言開發的編譯器和解釋器設計。

3. 儘可能不要使用解釋器模式,後期維護很是麻煩。在項目中,可使用JRuby、Groovy、Java的JavaScript引擎來代替解釋器,彌補Java語言不足。

應用場景

1. EL表達式的處理。

2. 正則表達式解釋器。

3. SQL語法解釋器。

4. 數學表達式解析器,如工具包Math Expression String Parser、Expression4J。

訪問者模式(Visitor)

效果

1. 不經常使用的設計模式。

2. 對於存儲在一個集合中的對象,他們可能具備不一樣的類型(即便有一個公共的接口),對於該集合中的對象,能夠接收一類稱爲訪問者的對象來訪問,不一樣的訪問者其訪問方式也有所不一樣。

3. 表示一個做用於某對象結構中各元素的操做,使咱們能夠不在改變元素類的前提下定義做用於這些元素的新操做。

應用場景

1. XML文檔解析器設計。

2. 編譯器的設計。

3. 複雜集合對象的處理。

策略模式(Strategy)

效果

1. 策略模式對應於解決某一個問題的一個算法族,容許客戶端從該算法族中任選一個算法解決問題,同時能夠方便更換算法或添加新的算法。

2. 本質:分離算法,選擇實現。

代碼

1. 某個市場人員接到單後的報銷策略(CRM系統的常見問題)。報價策略很複雜:

    a) 普通客戶小批量報價;

    b) 普通客戶大批量報價;

    c) 老客戶小批量報價;

    d) 老客戶大批量報價。

2. Strategy.java

1 public interface Strategy {
2 
3     double getPrice(double standardPrice);
4     
5 }
View Code

3. Context.java

 1 // 負責與具體的策略類交互,將客戶端與算法分離
 2 public class Context {
 3 
 4     private Strategy strategy;
 5 
 6     public Context(Strategy strategy) {
 7         this.strategy = strategy;
 8     }
 9     
10     public void printPrice(double standardPrice) {
11         System.out.println(strategy.getPrice(standardPrice));
12     }
13     
14 }
View Code

4. NewCustomerFewStrategy.java

1 public class NewCustomerFewStrategy implements Strategy {
2 
3     @Override
4     public double getPrice(double standardPrice) {
5         System.out.println("不打折!");
6         return standardPrice;
7     }
8 
9 }
View Code

5. NewCustomerManyStrategy.java

1 public class NewCustomerManyStrategy implements Strategy {
2 
3     @Override
4     public double getPrice(double standardPrice) {
5         System.out.println("打九折!");
6         return standardPrice * 0.9;
7     }
8 
9 }
View Code

6. OldCustomerFewStrategy.java

1 public class OldCustomerFewStrategy implements Strategy {
2 
3     @Override
4     public double getPrice(double standardPrice) {
5         System.out.println("打八五折!");
6         return standardPrice * 0.85;
7     }
8 
9 }
View Code

7. OldCustomerManyStrategy.java

1 public class OldCustomerManyStrategy implements Strategy {
2 
3     @Override
4     public double getPrice(double standardPrice) {
5         System.out.println("打八折!");
6         return standardPrice * 0.8;
7     }
8 
9 }
View Code

8. Client.java

1 public class Client {
2 
3     public static void main(String[] args) {
4         Strategy strategy = new OldCustomerManyStrategy();    // 可經過配置生成
5         Context context = new Context(strategy);
6         context.printPrice(998);
7     }
8 
9 }
View Code

應用場景

1. Java的GUI編程,佈局管理。

2. Spring框架的Resource接口,資源訪問策略。

3. javax.servlet.http.HttpServlet#service()。

模板方法模式(Template Method)

效果

1. 經常使用的模式。

2. 模板方法定義一個操做的算法框架,將某些步驟延遲到子類中實現。這樣,新的子類能夠在不改變算法結構的前提下,從新定義該算法的某些特定步驟。

代碼

1. BankTemplateMethod.java

 1 public abstract class BankTemplateMethod {
 2     
 3     protected void takeNumber() {
 4         System.out.println("取號!");
 5     }
 6 
 7     protected void waitInLine() {
 8         System.out.println("排隊!");
 9     }
10     
11     // 鉤子方法/回調方法:辦理具體業務
12     protected abstract void transaction();
13     
14     protected void evaluate() {
15         System.out.println("評分!");
16     }
17     
18     // 模板方法
19     public final void process() {
20         takeNumber();
21         waitInLine();
22         transaction();
23         evaluate();
24     }
25     
26 }
View Code

2. DrawMoney.java

1 public class DrawMoney extends BankTemplateMethod {
2 
3     @Override
4     protected void transaction() {
5         System.out.println("取款!");
6     }
7 
8 }
View Code

3. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         BankTemplateMethod drawMoney = new DrawMoney();
 5         drawMoney.process();
 6         
 7         // 匿名內部類實現
 8         new BankTemplateMethod() {
 9 
10             @Override
11             protected void transaction() {
12                 System.out.println("存款!");
13             }
14             
15         }.process();;
16     }
17 
18 }
View Code

應用場景

1. 各框架、類庫都有模板方法。

2. 數據庫訪問的封裝。

3. JUnit單元測試。

4. Servlet的doGet()和doPost()方法調用。

5. Spring的JDBCTemplate、HibernateTemplate。

狀態模式(State)

效果

1. 用於解決系統中複雜對象的狀態轉換以及不一樣狀態下行爲的封裝問題。

2. 酒店系統中,房間的狀態變化。

核心角色

1. 上下文類(Context):環境類中維護一個State對象,定義了當前的狀態。

2. 抽象狀態類(State)。

3. 具體狀態類(ConcreteState):每個類封裝了一個狀態對應的行爲。

代碼

1. State.java

1 public interface State {
2 
3     void handle();
4     
5 }
View Code

2. RoomContext.java

 1 public class RoomContext {
 2 
 3     private State state;
 4 
 5     public State getState() {
 6         return state;
 7     }
 8 
 9     public void setState(State state) {
10         this.state = state;
11         state.handle();
12     }
13     
14 }
View Code

3. FreeState.java

1 public class FreeState implements State {
2 
3     @Override
4     public void handle() {
5         System.out.println("退出房間!");
6     }
7 
8 }
View Code

4. BookedState.java

1 public class BookedState implements State {
2 
3     @Override
4     public void handle() {
5         System.out.println("預約房間!");
6     }
7 
8 }
View Code

5. CheckedInState.java

1 public class CheckedInState implements State {
2 
3     @Override
4     public void handle() {
5         System.out.println("入住房間!");
6     }
7 
8 }
View Code

6. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         RoomContext context = new RoomContext();
 5         context.setState(new FreeState());
 6         context.setState(new BookedState());
 7         context.setState(new CheckedInState());
 8     }
 9 
10 }
View Code

應用場景

1. 銀行系統的帳號狀態管理。

2. OA系統的公文狀態管理。

3. 酒店系統的房間狀態管理。

4. 線程對象各狀態之間的切換。

觀察者模式(Observer)

效果

1. 觀察者模式用於1:N的消息通知。

2. 當目標對象(Subject或Observable)的狀態變化(消息發佈)時,他及時告知一系列觀察者對象(Observer),令他們作出相應(消息訂閱)。

3. 通知觀察者的方式:

    a) 推:每次都會把消息以廣播方式發送給全部觀察者,全部觀察者只能被動接收。

    b) 拉:觀察者只要知道有變化便可,何時獲取消息、獲取什麼內容,都由觀察者自主決定。

代碼

1. Subject.java

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public abstract class Subject {
 5 
 6     private List<Observer> observers = new ArrayList<>();
 7     
 8     public void subscribe(Observer observer) {
 9         observers.add(observer);
10     }
11     
12     public void unsubscribe(Observer observer) {
13         observers.remove(observer);
14     }
15     
16     public void notifyAllObservers() {
17         for (Observer observer : observers) {
18             observer.update(this);
19         }
20     }
21     
22 }
View Code

2. ConcreteSubject.java

 1 public class ConcreteSubject extends Subject {
 2 
 3     private int state;
 4 
 5     public int getState() {
 6         return state;
 7     }
 8 
 9     public void setState(int state) {
10         this.state = state;
11         notifyAllObservers();
12     }
13     
14 }
View Code

3. Observer.java

1 public interface Observer {
2 
3     void update(Subject subject);
4     
5 }
View Code

4. ConcreteObserver.java

 1 public class ConcreteObserver implements Observer {
 2     
 3     private String name;
 4 
 5     public ConcreteObserver(String name) {
 6         this.name = name;
 7     }
 8 
 9     @Override
10     public void update(Subject subject) {
11         System.out.println(name + "收到消息:state=" + ((ConcreteSubject) subject).getState());
12     }
13 
14 }
View Code

5. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         ConcreteSubject subject = new ConcreteSubject();
 5         Observer observer1 = new ConcreteObserver("張三");
 6         Observer observer2 = new ConcreteObserver("李四");
 7         Observer observer3 = new ConcreteObserver("王五");
 8         subject.subscribe(observer1);
 9         subject.subscribe(observer2);
10         subject.subscribe(observer3);
11         
12         subject.setState(1);
13         subject.setState(2);
14     }
15 
16 }
View Code

代碼(基於JDK)

1. ConcreteSubject.java

 1 import java.util.Observable;
 2 
 3 public class ConcreteSubject extends Observable {
 4 
 5     private int state;
 6 
 7     public int getState() {
 8         return state;
 9     }
10 
11     public void setState(int state) {
12         this.state = state;
13         // 目標對象已變化
14         setChanged();
15         // 通知觀察者
16         notifyObservers(state);
17     }
18     
19 }
View Code

2. ConcreteObserver.java

 1 import java.util.Observable;
 2 import java.util.Observer;
 3 
 4 public class ConcreteObserver implements Observer {
 5 
 6     private String name;
 7 
 8     public ConcreteObserver(String name) {
 9         this.name = name;
10     }
11     
12     @Override
13     public void update(Observable observable, Object arg) {
14         ConcreteSubject subject = (ConcreteSubject) observable;
15         System.out.println(name + "收到消息:" + arg);
16         System.out.println(name + "獲取最新狀態:" + subject.getState());
17     }
18 
19 }
View Code

3. Client.java

 1 import java.util.Observer;
 2 
 3 public class Client {
 4 
 5     public static void main(String[] args) {
 6         ConcreteSubject subject = new ConcreteSubject();
 7         Observer observer1 = new ConcreteObserver("張三");
 8         Observer observer2 = new ConcreteObserver("李四");
 9         Observer observer3 = new ConcreteObserver("王五");
10         subject.addObserver(observer1);
11         subject.addObserver(observer2);
12         subject.addObserver(observer3);
13         
14         subject.setState(1);
15         subject.setState(2);
16     }
17 
18 }
View Code

應用場景

1. 聊天室,服務器轉發給全部客戶端。

2. 網絡遊戲多人聯機對戰,服務器將客戶端的狀態進行分發。

3. 郵件訂閱。

4. Servlet編程,監聽器的實現。

5. Android,廣播機制。

6. 京東商城,羣發某商品打折信息。

備忘錄模式(Memento)

效果

保存某個對象內部狀態的拷貝,之後能夠將該對象恢復到原先狀態。

核心角色

1. 源發器類(Originator):負責建立一個備忘錄類,用以記錄當前內部狀態,並可以使用備忘錄恢復內部狀態。

2. 備忘錄類(Memento):負責存儲源發器類的內部狀態,並可防止源發器類之外的其餘對象訪問備忘錄類。

3. 負責人類(CareTaker):負責保存好備忘錄,備忘點較多時,可用List或Stack存儲。也能夠持久化。

代碼

1. Employee.java

 1 // 源發器類
 2 public class Employee {
 3 
 4     private String name;
 5     
 6     private int age;
 7     
 8     private double salary;
 9 
10     public Employee(String name, int age, double salary) {
11         this.name = name;
12         this.age = age;
13         this.salary = salary;
14     }
15     
16     // 備忘
17     public EmployeeMemento memento() {
18         return new EmployeeMemento(this);
19     }
20     
21     // 恢復
22     public void recover(EmployeeMemento employeeMemento) {
23         this.name = employeeMemento.getName();
24         this.age = employeeMemento.getAge();
25         this.salary = employeeMemento.getSalary();
26     }
27 
28     public String getName() {
29         return name;
30     }
31 
32     public void setName(String name) {
33         this.name = name;
34     }
35 
36     public int getAge() {
37         return age;
38     }
39 
40     public void setAge(int age) {
41         this.age = age;
42     }
43 
44     public double getSalary() {
45         return salary;
46     }
47 
48     public void setSalary(double salary) {
49         this.salary = salary;
50     }
51     
52     @Override
53     public String toString() {
54         return "name=" + name + ",age=" + age + ",salary=" + salary;
55     }
56     
57 }
View Code

2. EmployeeMemento.java

 1 public class EmployeeMemento {
 2 
 3     private String name;
 4 
 5     private int age;
 6 
 7     private double salary;
 8 
 9     public EmployeeMemento(Employee employee) {
10         this.name = employee.getName();
11         this.age = employee.getAge();
12         this.salary = employee.getSalary();
13     }
14 
15     public String getName() {
16         return name;
17     }
18 
19     public int getAge() {
20         return age;
21     }
22 
23     public double getSalary() {
24         return salary;
25     }
26     
27 }
View Code

3. EmployeeCareTaker.java

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public class EmployeeCareTaker {
 5 
 6     private List<EmployeeMemento> mementoes = new ArrayList<>();
 7     
 8     public void addMemento(EmployeeMemento mementoe) {
 9         mementoes.add(mementoe);
10     }
11     
12     public EmployeeMemento getMemento(int index) {
13         return mementoes.get(index);
14     }
15     
16     public EmployeeMemento getLastMemento() {
17         return getMemento(mementoes.size() - 1);
18     }
19     
20 }
View Code

4. Client.java

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         EmployeeCareTaker careTaker = new EmployeeCareTaker();
 5         
 6         Employee employee = new Employee("張三", 18, 1000);
 7         System.out.println(employee);
 8         
 9         careTaker.addMemento(employee.memento());
10         employee.setAge(20);
11         employee.setSalary(3000);
12         System.out.println(employee);
13         careTaker.addMemento(employee.memento());
14         
15         employee.setAge(21);
16         System.out.println(employee);
17         
18         employee.recover(careTaker.getLastMemento());
19         System.out.println(employee);
20     }
21 
22 }
View Code

應用場景

1. 棋類遊戲的悔棋。

2. 編輯軟件的撤銷操做。

3. 數據庫的事務回滾操做。

4. Photoshop的歷史版本記錄。

 

做者:netoxi
出處:http://www.cnblogs.com/netoxi本文版權歸做者和博客園共有,歡迎轉載,未經贊成須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。歡迎指正與交流。

相關文章
相關標籤/搜索