1.面向對象的三大特性

1)封裝(Encapsulation)

隐藏對象的具體實現細節,通過共有方法暴露對象的功能。内部結構可以自由修改,同時可對成員進行更加精确的控制 (比如在setter方法中加值合法判斷)

2)繼承(Inheritance)

使用已經存在的類作為基礎類(父類),在此基礎上建立新類(子類), 子類既可複用父類的功能,也能進行擴展,從而實現代碼複用。 另外,Java不能像C++那樣同時繼承多個父類,隻能樹形的繼承, 比如:Man -> Human -> Animal,或通過接口和内部類實現多繼承。

另外,關于繼承還需注意以下幾點:

  • 1.子類擁有父類非private的屬性與方法
  • 2.構造方法隻能調用,不能實現,子類默認調用父類的無參構造方法,
    如果父類沒有無參的構造方法,需要使用super顯式調用!
  • 3.慎用繼承,要考慮是否需要從子類向父類進行向上轉型!

3)多态(Polymorphism)

定義:一個類實例的相同方法在不同的情形下有不同的表現形式

分為以下兩種:

  • 編譯時多态(OverLoading)—— 方法重載
  • 運行時多态(OverRidding)—— 繼承 + 方法重寫 + 向上轉型(父類引用指向子類對象)

運行時多态(動态綁定,new後面什麼類型,動态類型就是什麼類型)

示例如下:

C++代碼
  1. class Animal() { fun show() { println("動物") }}  
  2. class People:Animal() { fun show() { println("人類") }}  
  3. //下述代碼打印結果:人類  
  4. Animal animal = new People()  
  5. animal.show()

2.類與類間的關系

口訣雞濕衣冠劇組(繼承,實現,依賴,關聯,聚合,組合)

繼承和實現就不說了,後面四個隻是 語意層次 的區别
兩個類的相關程度,依賴 < 關聯 < 聚合 < 組合

依次的UML類圖标記:

  • 繼承/泛化(Generalization): 子類 父類

  • 實現(Realization):實現類 接口

  • 依賴(Dependency):不持有引用,具體表現:局部變量,函數參數,
    返回值使用 依賴類,比如大佬依賴于遞茶小弟;

  • 關聯(Association):持有引用,具體表現:成員變量, 箭頭指向被關聯類,可雙向,一對多或多對多:

  • 聚合(Aggregation):成員變量,關聯是處于同一層次的,而聚合則 是整體和局部層次的,比如:社團小弟,另外即使沒有了社團, 小弟們依舊可以到别的地方搞事情。

  • 組合(Composition):與聚合類似,程度更加強烈,共生死,組合類 負責被組合類的生命周期,比如: 社團大佬,如果沒了社團, 大佬也就就不能存在了。


3.面向對象七大原則

  • 單一職責原則(Single Responsibility Principle)
    每一個類應該專注于做一件事情。 即:高内聚,低耦合。

  • 開閉原則(Open Close Principle)
    一個對象對擴展開放對修改關閉。即:對類的改動是通過增加代碼進行的,而不是修改現有代碼。

  • 裡氏替換原則(Liskov Substitution Principle)
    在任何父類出現的地方都可以用它的子類來替代。

  • 依賴倒置原則(Dependence Inversion Principle)
    要依賴于抽象不要依賴于具體實現

  • 接口隔離原則(Interface Segregation Principle)
    應當為客戶端提供盡可能小的單獨的接口,而不是提供大的總的接口。

  • 迪米特原則(Law Of Demeter)
    一個對象應當盡量少地與其他對象之間發生相互作用,使得系統功能模塊相對獨立。

  • 組合/聚合複用原則(Composite/Aggregate Reuse Principle)
    盡量使用組合/聚合的方式,而不是使用繼承


23種設計模式

  • 創建型(5種):主要用于處理對象的創建,實例化對象:
    單例建造者原型工廠方法抽象工廠

  • 結構型(7種):處理類或對象間的組合
    适配器裝飾者結合橋接外觀享元代理

  • 行為型(11種):描述類或對象怎樣進行交互和職責分配
    策略觀察者疊代器命令備忘錄中介者解釋器訪問者責任鍊狀态模闆方法


一. 單例模式(Singleton Pattern)

作用:保證 類在内存中對象唯一性

适用場景

  • 1.避免創建多個實例浪費資源
  • 2.避免多個實例因多次調用而出現錯誤
  • 3.一般寫工具類,線程池,緩存,數據庫會用到。

套路(三個要點):

  • 1.不允許在類外new對象 —— 構造方法私有化
  • 2.在類中創建對象 —— 通過new在本類中創建一個實例
  • 3.對外提供獲取該實例的方法 —— 定義公有方法返回創建的實例

餓漢與懶漢的區别

前者在類裝載時就實例化,後者隻有在第一次被使用時才實例化。 (餓漢的優點是避免線程同步問題,缺點是即使沒用到這個實例還是會加載) (懶漢的優點是實現了懶加載,但需要解決線程安全問題!)

7種單例套路

1)餓漢式,沒有實現懶加載~

Java代碼
  1. public class Singleton() {  
  2.     private static Singleton instance = new Singleton();  
  3.     private Singleton(){ }  
  4.     public static Singleton getInstance() {   
  5.         return instance;    
  6.     }  
  7. }  
  8. //獲取單例對象  
  9. Singleton mSingleton = Singleton.getInstance();

2)懶漢式

雖然達到了懶加載,但是卻存在線程安全問題,比如有兩個線程都剛好執行完if(instance == null),接着準備執行instance = new Singleton() 語句,這樣的結果會導緻我們實例化了兩個Singleton對象,為了解決線程不安全問題,可以對getInstance()方法加鎖。

Java代碼
  1. public class Singleton {  
  2.     private static Singleton instance = null;  
  3.     private Singleton() { }  
  4.     private static Singleton getInstance() {  
  5.         if(instance == null) {   
  6.             instance = new Singleton();   
  7.         }  
  8.         return instance;  
  9.     }  
  10. }

3)懶漢式加鎖版

為getInstance方法加鎖雖然保證了線程安全,但是每次執行getInstance() 都需要同步,而實例化對象隻需要執行一次就夠了,後面獲取該示例, 應該直接return就好了,方法同步效率太低,一種改進後的寫法是: synchronized (Singleton.class) { instance = new Singleton(); } 但是,這樣寫依然是線程不安全的,如果你還是想用懶漢式的話,推薦雙重檢查鎖定(DCL,Double Check Lock)。

Java代碼
  1. public class Singleton {  
  2.     private static Singleton instance = null;  
  3.     private Singleton() { }  
  4.     private static synchronized Singleton getInstance() {  
  5.         if(instance == null) {   
  6.             instance = new Singleton();   
  7.         }  
  8.         return instance;  
  9.     }  
  10. }

4)懶漢式雙重校驗鎖(DCL)

代碼中進行了兩次if檢查,這樣就可以保證線程安全,初始化一次後,後面再次訪問時,if檢查,直接return 實例化對象。volatile是1.5後引入的,volatile關鍵字會屏蔽Java虛拟機所做的一些代碼優化,會導
緻系統運行效率降低,而更好的寫法是使用靜态内部類來實現單例!

Java代碼
  1. public class Singleton{  
  2.     private static volatile Singleton instance = null;  
  3.     private Singleton() { }  
  4.     public static Singleton getInstance() {  
  5.         if(instance == null) {  
  6.             synchronized(Singleton.class) {  
  7.                 if(instance == null) instance = new Singleton();  
  8.             }  
  9.         }  
  10.         return instance;  
  11.     }  
  12.  }

5)靜态内部類實現單例(推薦)

和餓漢式類似,都是通過類加載機制來保證初始化實例的時候隻有一個線程,從而避免線程安全問題,餓漢式的Singleton類被加載時,就會實例化,而靜态内部類這種,當Singleton類被加載時,不會立即實例化,調用getInstance() 方法才會裝載SingletonHolder類,從而完成Singleton的實例化。

Java代碼
  1. public class Singleton {  
  2.     private Singleton() { }  
  3.     private static final Singleton getInstance() {  
  4.         return SingletonHolder.INSTANCE;  
  5.     }  
  6.     private static class SingletonHolder {  
  7.         private static final Singleton INSTANCE = new Singleton()  
  8.     }  
  9. }

6)枚舉實現單例

INSTANCE即為SingletonEnum類型的引用,得到它就可以調用
枚舉中的方法。既避免了線程安全問題,還能防止反序列化
重新創建新的對象,但是失去了類的一些特性,而且沒有延時加載。

Java代碼
  1. public enum SingletonEnum {  
  2.     INSTANCE;  
  3.     private Singleton instance;  
  4.     SingletonEnum() {   
  5.         instance = new Singleton();  
  6.     }  
  7.     public Singleton getInstance() {   
  8.         return instance;   
  9.     }  
  10. }  
  11. //調用方式  
  12. SingletonEnum.INSTANCE.method(); 

7)容器實現單例

将多種單例類型注入到一個統一的管理類中,在使用時根據key獲取對象
對應類型的對象。這種方式使得我們可以管理多種類型的單例,并且在使
用時可以通過統一的接口進行獲取操作,降低了用戶的使用成本,也對用
戶隐藏了具體實現,降低了耦合度。

Java代碼
  1. public class SingletonManager {  
  2.     private static Map<String,Object> objMap = new HashMap<String,Object>();  
  3.     private Singleton(){ }  
  4.     public static void registerService(String key,Object instance) {  
  5.         if(!objMap.containsKey(key)) {  
  6.             objMap.put(key,instance);  
  7.         }  
  8.     }  
  9.     public static Object getService(String key) {  
  10.         return objMap.get(key);  
  11.     }  
  12. }

二. 建造者模式(Builder Pattern)

複雜對象的構建與表示分離 開來,使得同樣的構建過程可以創建不同的表示,缺點是可能産生多餘的創建者與構建過程對象,消耗内存,不适用于内部建造順序不穩定,變化複雜的對象,可能導緻需要創建很多具體的建造者來實現這些變化。

例子:玩遊戲創建角色時的自定義,不同的搭配生成不同的角色。

四個角色與UML類圖

示例代碼

Java代碼
  1. //産品類  
  2. class Character {  
  3.     private String sex;  
  4.     private String face;  
  5.     private String clothes;  
  6.   
  7.     void setSex(String sex) { this.sex = sex;}  
  8.     void setFace(String face) { this.face = face; }  
  9.     void setClothes(String clothes) { this.clothes = clothes;}  
  10.   
  11.     String showMsg() { return "你創建了一個穿着 " + clothes + " 一副 " + face + " 的" + sex + "ヾ(≧▽≦*)o 戳菊狂笑~"; }  
  12. }  
  13.   
  14. //抽象Builder接口  
  15. interface Builder {  
  16.     void setSex(String sex);  
  17.     void setFace(String face);  
  18.     void setClothes(String clothes);  
  19.     Character build();  
  20. }  
  21.   
  22. //Builder接口實現類  
  23. class ConcreteBuilder implements Builder {  
  24.     private Character mCharacter = new Character();  
  25.   
  26.     @Override public void setSex(String sex) { mCharacter.setSex(sex); }  
  27.     @Override public void setFace(String face) { mCharacter.setFace(face); }  
  28.     @Override public void setClothes(String clothes) { mCharacter.setClothes(clothes); }  
  29.     @Override public Character build() {return mCharacter;}  
  30. }  
  31.   
  32. //裝配過程類  
  33. class Director {  
  34.     private Builder mBuilder = null;  
  35.     Director(Builder builder) { this.mBuilder = builder; }  
  36.     Character createCharacter(String sex, String face, String clothes) {  
  37.         this.mBuilder.setSex(sex);  
  38.         this.mBuilder.setFace(face);  
  39.         this.mBuilder.setClothes(clothes);  
  40.         return mBuilder.build();  
  41.     }  
  42. }  
  43.   
  44. //客戶端調用類  
  45. public class Game {  
  46.     public static void main(String[] args) {  
  47.         Builder builder = new ConcreteBuilder();  
  48.         Director director = new Director(builder);  
  49.         Character character =  director.createCharacter("基佬","硬漢臉","死庫水");  
  50.         System.out.println(character.showMsg());  
  51.     }  
  52. }

輸出結果


三. 原型模式(Prototype Pattern)

下面兩種場景可以考慮使用原型模式:

  • 1.當初始化類對象需要消耗非常多資源,或者說要進行繁瑣
    的數據準備或者權限,如果想簡化創建,可以使用原型模式。
  • 2.一個對象提供給其他對象訪問,而各個調用者可能都需要
    修改對象的值,可以考慮使用原型模式克隆多個對象供調用者
    使用(保護性拷貝

三個角色與UML類圖

Java中 == 與equals的區别

  • ==基本數據類型(int,long等),比較存儲的值是否相等
    對比的是引用類型,比較的是所指對象地址是否相等

  • equals,不能用于比較基本數據類型,如果**沒對equals()方法進行重寫,比較的是指向的對象地址,如果想要比較對象内容,需要自行重寫**方法,做相應的判斷!!!!String調equals是可以判斷内容是否一樣,是因為對equals()方法進行了重寫,具體可參見源碼!

克隆需要滿足的三個條件

  • 1.x.clone()!=x ,即 不是同一對象
  • 2.x.clone().getClass == x.getClass(),即 對象類型一緻
  • 3.如果對象obj的equals()方法定義恰當的話,那麼
    obj.clone().equals(obj) == true應當是成立的。(推薦,不強制)

Java中如何使用

Prototype原型類(想被克隆的類)實現Cloneable接口重寫clone()方法。

Java代碼
  1. ConcretePrototype cp1 = new ConcretePrototype();   
  2. ConcretePrototype cp2 = (ConcretePrototype)cp1.clone(); 

需注意

  • 1.執行克隆方法,不會調用構造方法
  • 2.克隆會生成的新的對象成員,但指向的卻是同一個内存地址
  • 3.克隆前後數據類型一緻
  • 4.克隆的時候,類中基本數據類型的屬性會新建,但是引用類型
    隻會生成個新的引用變量,引用變量的地址依舊指向同一個内存地址!

實現深拷貝的兩種套路

這種隻新建基本類型數據,不新建引用類型數據,稱為淺拷貝,如果連引用類型數據也新建的話,則稱為深拷貝

兩個套路:

1.引用類型也實現Cloneable接口,如果屬性的類型也是對象,那麼需要一直遞歸的克隆下去
2.序列化,屬性的類型是引用類型的話,需要實現Serializable接口,然後自己寫個方法來在裡面**完成對象轉二進制流與二進制流轉對象**的方法,然後返回克隆後的對象!

具體代碼見:3.Prototype Pattern


四.工廠方法模式(Factory Method Pattern)

關于三種工廠模式,其實理解起來非常簡單,隻是把對象的創建放到一個特定的類中,相比起我們直接new對象,這種套路會寫多幾個類,但是卻擁有更好的擴展性,而且當創建的對象發生改變,可以減少一定的修改量。(想想你在項目中有一個類在多處都new了,現在需要對這個類的構造方法,或者相關參數做些修改,你需要找到每個new這個類的地方進行修改,而如果你把工作都丢給一個工廠類,你可能隻需要修改這個類) 另外,簡介下這幾種工廠模式的區别:

  • 簡單工廠模式:最簡單的直接把new對象丢到一個工廠類中;
  • 工廠方法模式:對工廠類進行抽象,實現具體工廠類以創建不同對象;
  • 抽象工廠模式:當工廠需要創建多種相互關聯或依賴的對象,有兩個名
    産品等級結構産品族,具體是什麼的自己看~

簡單工廠模式的三個角色

代碼示例

Java代碼
  1. abstract class Tea {  
  2.     public abstract void 加奶茶();  
  3.     public abstract void 加料();  
  4. }  
  5.   
  6. class YeGuoTea extends Tea{  
  7.     @Override public void 加奶茶() { System.out.println("加了一把奶茶");}  
  8.     @Override public void 加料() {System.out.println("加了一把椰果");}  
  9. }  
  10.   
  11. class ZhenZhuTea  extends Tea{  
  12.     @Override public void 加奶茶() { System.out.println("加了一把奶茶");}  
  13.     @Override public void 加料() {System.out.println("加了一把珍珠");}  
  14. }  
  15.   
  16. public class Me {  
  17.     public static Tea makeTea(int type) {  
  18.         System.out.println("==============");  
  19.         Tea tea = type == 0 ? new ZhenZhuTea() : new YeGuoTea();  
  20.         tea.加奶茶();  
  21.         tea.加料();  
  22.         return tea;  
  23.     }  
  24. }  
  25.   
  26. public class Store {  
  27.     public static void main(String[] args) {  
  28.         for (int i = 0;i < 3;i++) {  
  29.             Tea tea = Me.makeTea(buyTea()); //小豬制作奶茶  
  30.         }  
  31.     }  
  32.   
  33.     /* 模拟用戶下單,0代表要珍珠奶茶,1代表要椰果奶茶 */  
  34.     private static int buyTea() {  
  35.         return new Random().nextInt(2);  
  36.     }  

輸出結果


工廠方法模式(靜态工廠)

其實就是在簡單工廠模式基礎上,把工廠創建不同産品的内部邏輯抽取出來,生成一個抽象工廠,再創建具體工廠類,生産不同的産品。

UML類圖

代碼示例

Java代碼
  1. //工廠接口/抽象類  
  2. abstract class MakeTea {  
  3.     abstract Tea 小豬帶特效的奶茶制作工藝();  
  4. }  
  5.   
  6. //工廠實現類1  
  7. class ZhenZhuMakeTea extends MakeTea {  
  8.     @Override  
  9.     Tea 小豬帶特效的奶茶制作工藝() {  
  10.         System.out.println("====== 珍珠小弟炮制港式珍珠奶茶 ======");  
  11.         Tea tea = new ZhenZhuTea();  
  12.         tea.加奶();  
  13.         tea.加茶();  
  14.         tea.加料();  
  15.         tea.打包();  
  16.         return tea;  
  17.     }  
  18. }  
  19.   
  20. //工廠實現類2  
  21. class YeGuoMakeTea extends MakeTea {  
  22.     @Override  
  23.     Tea 小豬帶特效的奶茶制作工藝() {  
  24.         System.out.println("====== 椰果小弟炮制日式椰果奶茶 ======");  
  25.         Tea tea = new YeGuoTea();  
  26.         tea.加奶();  
  27.         tea.加茶();  
  28.         tea.加料();  
  29.         tea.打包();  
  30.         return tea;  
  31.     }  
  32. }  
  33.   
  34. //客戶端調用  
  35. public class StoreS {  
  36.     public static void main(String[] args) {  
  37.         //初始化兩個小弟  
  38.         ZhenZhuMakeTea zhenzhu = new ZhenZhuMakeTea();  
  39.         YeGuoMakeTea yeguo = new YeGuoMakeTea();  
  40.   
  41.         for (int i = 0;i < 3;i++) {  
  42.             Tea tea = buyTea() == 0 ? zhenzhu.小豬帶特效的奶茶制作工藝()   
  43.                 : yeguo.小豬帶特效的奶茶制作工藝();  
  44.         }  
  45.     }  
  46.   
  47.     /* 模拟用戶下單,0代表要珍珠奶茶,1代表要椰果奶茶 */  
  48.     private static int buyTea() {  
  49.         return new Random().nextInt(2);  
  50.     }  

輸出結果

另外還可以通過反射簡潔生産過程,直接傳入産品的類類型,生成對應的産品,示例如下:

Java代碼
  1. abstract class SMakeTea {  
  2.     public abstract <T extends Tea> T 小豬帶特效的奶茶制作工藝(Class<T> clz);  
  3. }  
  4.   
  5. class SMe extends SMakeTea {  
  6.     @Override  
  7.     public <T extends Tea> T 小豬帶特效的奶茶制作工藝(Class<T> clz) {  
  8.         System.out.println("==============");  
  9.         Tea tea = null;  
  10.         try {  
  11.             tea = (Tea) Class.forName(clz.getName()).newInstance();  
  12.             tea.加奶();  
  13.             tea.加茶();  
  14.             tea.加料();  
  15.             tea.打包();  
  16.         } catch (Exception e) {  
  17.             e.printStackTrace();  
  18.         }  
  19.         return (T) tea;  
  20.     }  
  21. }  
  22.   
  23. public class SStore {  
  24.     public static void main(String[] args) {  
  25.         SMe me = new SMe();  
  26.         me.小豬帶特效的奶茶制作工藝(ZhenZhuTea.class);  
  27.         me.小豬帶特效的奶茶制作工藝(YeGuoTea.class);  
  28.     }  
  29. }

六. 抽象工廠模式(Abstract Factory Pattern)

代碼示例

Java代碼
  1. //抽象産品類1  
  2. abstract class Drink {  
  3.     public abstract void drink();  
  4. }  
  5.   
  6. //抽象産品類2  
  7. abstract class Snack {  
  8.     public abstract void snack();  
  9. }  
  10.   
  11. //具體産品類們  
  12. class MilkTea extends Drink {  
  13.     @Override public void drink() { System.out.println("一杯奶茶"); }  
  14. }  
  15.   
  16. class Juice extends Drink {  
  17.     @Override public void drink() { System.out.println("一杯果汁"); }  
  18. }  
  19.   
  20. class HandGrab extends Snack {  
  21.     @Override public void snack() { System.out.println("一個手抓餅"); }  
  22. }  
  23.   
  24. class FishBall extends Snack {  
  25.     @Override public void snack() { System.out.println("一碗魚蛋"); }  
  26. }  
  27.   
  28. //抽象工廠類  
  29. abstract class MakeFood {  
  30.     abstract Drink createMakeDrink();  
  31.     abstract Snack createMakeSnack();  
  32. }  
  33.   
  34. //具體工廠類1  
  35. class FirstXiaoDi extends MakeFood {  
  36.     @Override public Drink createMakeDrink() { return new MilkTea(); }  
  37.     @Override public Snack createMakeSnack() { return new HandGrab(); }  
  38. }  
  39.   
  40. //具體工廠類2  
  41. class SecondXiaoDi extends MakeFood {  
  42.     @Override public Drink createMakeDrink() { return new Juice(); }  
  43.     @Override public Snack createMakeSnack() { return new FishBall(); }  
  44. }  
  45.   
  46. //客戶端調用  
  47. public class Store {  
  48.     public static void main(String[] args) {  
  49.         //初始化兩個小弟  
  50.         MakeFood xiaodi1 = new FirstXiaoDi();  
  51.         MakeFood xiaodi2 = new SecondXiaoDi();  
  52.   
  53.         for(int i = 0;i < 4 ;i++) {  
  54.             System.out.println("====== 根據訂單配餐: ======");  
  55.             Drink drink = buyDrink() == 0 ?  
  56.                 xiaodi1.createMakeDrink() : xiaodi2.createMakeDrink();  
  57.             Snack snack = buySnack() == 0 ?   
  58.                 xiaodi1.createMakeSnack() : xiaodi2.createMakeSnack();  
  59.             drink.drink();  
  60.             snack.snack();  
  61.         }  
  62.     }  
  63.   
  64.     /* 模拟用戶點飲料,0代表要奶茶,1代表要果汁 */  
  65.     private static int buyDrink() { return new Random().nextInt(2); }  
  66.   
  67.     /* 模拟用戶點小吃,0代表要手抓餅,1代表要魚蛋 */  
  68.     private static int buySnack() { return new Random().nextInt(2); }  
  69. }

輸出結果

兩個名詞(産品等級結構産品族)

  • 産品等級結構(繼承)
    比如這裡的抽象類是Drink(飲料),子類有奶茶,果汁,然後抽象飲料與具體飲料構成了一個産品等級結構,抽象飲料是父類,具體飲料是其子類。

  • 産品族
    同一工廠生産的,位于不同産品等級結構的一組産品,比如這裡的奶茶和果汁屬于飲料結構的一組産品,而手抓餅和魚蛋則屬于小吃結構的一組産品。

四個角色與UML類圖

抽象工廠模式适用于創建的對象有多個相互關聯或依賴的産品族;抽象工廠模式隔離具體類的生成,接口與實現分離,增加新的産品族很方便;但是擴展新的産品等級結構麻煩,需要修改抽象工廠,具體工廠類也要更改。


七. 适配器模式(Adapter Pattern)

兩個彼此間沒太大關聯的類,想進行交互完成某些事情,不想直接去修改各自的接口,可以添加一個中間類,讓他來協調兩個類間的關系,完成相關業務,這種模式就叫适配器模式。

然後分為:類适配器對象适配器 兩種,前者和适配者是繼承關系,後者與适配者則是引用關系。

對象适配器支持傳入一個被适配器對象,因此可以做到對多種被适配接口進行适配。而類适配器直接繼承無法動态修改,所以一般情況下對象适配器使用得更多!(Java不支持多重繼承!!!)

對象适配器例子(用得較多)

Java代碼
  1. /* 目标接口 */  
  2. interface Chinese {  
  3.     void speakChinese(String string);  
  4. }  
  5.   
  6. /* 需要适配的類 */  
  7. class English {  
  8.     void speakEnglish(String string) { System.out.println("【英語】" + string); }  
  9. }  
  10.   
  11. /* 适配器 */  
  12. class Translator implements Chinese{  
  13.     private English english = new English();  
  14.   
  15.     Translator(English english) { this.english = english; }  
  16.   
  17.     @Override public void speakChinese(String string) { english.speakEnglish(string); }  
  18. }  
  19.   
  20. /* 客戶端調用 */  
  21. public class Client {  
  22.     public static void main(String[] args) {  
  23.         Chinese chinese = new Translator(new English());  
  24.         chinese.speakChinese("那你很棒棒哦!");  
  25.     }  

輸出結果

類适配器例子

Java代碼
  1. /* 類适配器 */  
  2. class ClassTranslator extends English implements Chinese {  
  3.     @Override public void speakChinese(String string) { speakEnglish(string); }  
  4. }  
  5.   
  6. /* 客戶端調用 */  
  7. public class ClientC {  
  8.     public static void main(String[] args) {  
  9.         ClassTranslator translator = new ClassTranslator();  
  10.         translator.speakChinese("你也很好啊!");  
  11.     }  

輸出結果

除此之外還有個缺省适配器模式的名詞,簡單點說就是不需要實現接口中提供的所有方法時,先寫一個抽象類實現這個接口,然後為每個方法提供一個默認實現(空方法),然後選擇性覆蓋某些方法實現需求,又稱單接口适配器模式。


八.裝飾者模式(Decorator Pattern)

動态的給對象添加一些額外的職責,就增加功能來說,裝飾者模式比起生成子類更加靈活!就是想替代多重層繼承的模式。其實就是一層套一層

代碼示例

Java代碼
  1. /* 抽象組件 */  
  2. abstract class Tea {  
  3.     private String name = "茶";  
  4.   
  5.     public String getName() { return name; }  
  6.   
  7.     void setName(String name) { this.name = name; }  
  8.   
  9.     public abstract int price();  
  10. }  
  11.   
  12. /* 具體組件 */  
  13. class MilkTea extends Tea {  
  14.     MilkTea() { setName("奶茶"); }  
  15.   
  16.     @Override public int price() { return 5; }  
  17. }  
  18.   
  19. class LemonTea extends Tea{  
  20.     LemonTea() { setName("檸檬茶"); }  
  21.   
  22.     @Override public int price() { return 3; }  
  23. }  
  24.   
  25. /* 抽象裝飾類 */  
  26. abstract class Decorator extends Tea{  
  27.     public abstract String getName();  
  28. }  
  29.   
  30. /* 具體裝飾類 */  
  31. class ZhenZhu extends Decorator {  
  32.     Tea tea;  
  33.   
  34.     ZhenZhu(Tea tea) { this.tea = tea; }  
  35.   
  36.     @Override public String getName() { return "珍珠" + tea.getName(); }  
  37.   
  38.     @Override public int price() { return 2 + tea.price(); }  
  39. }  
  40.   
  41. class YeGuo extends Decorator{  
  42.     //...  
  43. }  
  44.   
  45. class JinJu extends Decorator{  
  46.     //...  
  47. }  
  48.   
  49. class HongDou extends Decorator{  
  50.     //...  
  51. }  
  52.   
  53. /* 客戶端調用 */  
  54. public class Store {  
  55.     public static void main(String[] args) {  
  56.         Tea tea1 = new MilkTea();  
  57.         System.out.println("你點的是:" + tea1.getName() + " 價格為:" + tea1.price());  
  58.   
  59.         Tea tea2 = new LemonTea();  
  60.         tea2 = new JinJu(tea2);  
  61.         System.out.println("你點的是:" + tea2.getName() + " 價格為:" + tea2.price());  
  62.   
  63.         Tea tea3 = new MilkTea();  
  64.         tea3 = new ZhenZhu(tea3);  
  65.         tea3 = new YeGuo(tea3);  
  66.         tea3 = new HongDou(tea3);  
  67.         tea3 = new JinJu(tea3);  
  68.         System.out.println("你點的是:" + tea3.getName() + " 價格為:" + tea3.price());  
  69.     }  
  70. }

輸出結果


九.組合模式(Composite Pattern)

部分-整體模式,把具有 相似的一組對象 當做一個對象處理,用一種 樹狀的結構組合對象,再提供統一的方法去訪問相似的對象,以此忽略掉對象與對象容器間的差别。

根節點枝結點葉子結點 三個名詞需要理解,類比上圖,根節點是菜單,枝結點是飲料菜單和小吃菜單,葉子結點是奶茶,果汁,手抓餅和魚蛋!

代碼示例

Java代碼
  1. /* 抽象組件 */  
  2. abstract class AbstractMenu {  
  3.     public abstract void add(AbstractMenu menu);  
  4.     public abstract AbstractMenu get(int index);  
  5.     public abstract String getString();  
  6. }  
  7.   
  8. /* 容器組件 */  
  9. class Menu extends AbstractMenu {  
  10.     private String name;  
  11.     private String desc;  
  12.     private List<AbstractMenu> menus = new ArrayList<>();  
  13.   
  14.     Menu(String name, String desc) {  
  15.         this.name = name;  
  16.         this.desc = desc;  
  17.     }  
  18.   
  19.     @Override public void add(AbstractMenu menu) { menus.add(menu); }  
  20.   
  21.     @Override public AbstractMenu get(int index) { return menus.get(index); }  
  22.   
  23.     @Override public String getString() {  
  24.         StringBuilder sb = new StringBuilder("\n【菜單】:" + name + " 信息:" + desc + "\n");  
  25.         for (AbstractMenu menu: menus) { sb.append(menu.getString()).append("\n"); }  
  26.         return sb.toString();  
  27.     }  
  28. }  
  29.   
  30. /* 葉子組件 */  
  31. class MilkTea extends AbstractMenu {  
  32.     private String name;  
  33.     private String desc;  
  34.     private int price;  
  35.   
  36.     MilkTea(String name, String desc, int price) {  
  37.         this.name = name;  
  38.         this.desc = desc;  
  39.         this.price = price;  
  40.     }  
  41.   
  42.     @Override public void add(AbstractMenu menu) { /*未使用*/ }  
  43.   
  44.     @Override public AbstractMenu get(int index) { return null; }  
  45.   
  46.     @Override public String getString() {  
  47.         return " - 【奶茶】* " + name + " 标注:" + desc + " 價格:" + price;  
  48.     }  
  49. }  
  50.   
  51. class MilkTea extends AbstractMenu {  
  52.     //...  
  53. }  
  54.   
  55. class HandCake  extends AbstractMenu {  
  56.     //...  
  57. }  
  58.   
  59. class FishBall  extends AbstractMenu {  
  60.     //...  
  61. }  
  62.   
  63. /* 客戶端調用 */  
  64. public class Store {  
  65.     public static void main(String[] args) {  
  66.         AbstractMenu mainMenu = new Menu("大菜單""包含所有子菜單");  
  67.         AbstractMenu drinkMenu = new Menu("飲品菜單""都是喝的");  
  68.         AbstractMenu eatMenu = new Menu("小吃菜單""都是吃的");  
  69.         AbstractMenu milkTea = new MilkTea("珍珠奶茶""奶茶+珍珠"5);  
  70.         AbstractMenu juice = new Juice("鮮榨猕猴桃枝""無添加即榨"8);  
  71.         AbstractMenu ball = new FishBall("咖喱魚蛋""微辣"6);  
  72.         AbstractMenu cake = new HandCake("培根手抓餅""正宗台灣風味"8);  
  73.   
  74.         drinkMenu.add(milkTea);  
  75.         drinkMenu.add(juice);  
  76.         eatMenu.add(ball);  
  77.         eatMenu.add(cake);  
  78.         mainMenu.add(drinkMenu);  
  79.         mainMenu.add(eatMenu);  
  80.   
  81.         System.out.println(mainMenu.getString());  
  82.     }  
  83. }

輸出結果


十.橋接模式(Bridge Pattern)

基于單一職責原則,如果系統中的類存在多個變化的維度,通過該模式可以将這幾個維度分離出來, 然後進行獨立擴展。這些分離開來的維度,通過在抽象層持有其他維度的引用來進行關聯,就好像在兩個維度間搭了橋一樣,所以叫橋接模式。

代碼示例(變化的三個維度:配餐,扒類)

Java代碼
  1. /* 抽象部分 */  
  2. abstract class Rations {  
  3.     abstract String rations();  
  4. }  
  5.   
  6. /* 擴展抽象部分 */  
  7. class Rice extends Rations {  
  8.     @Override public String rations() { return "飯"; }  
  9. }  
  10.   
  11. class Spaghetti extends Rations {  
  12.     @Override public String rations() { return "意粉"; }  
  13. }  
  14.   
  15. /* 實現部分 */  
  16. abstract class Steak {  
  17.     Rations rations;  
  18.   
  19.     Steak(Rations rations) { this.rations = rations; }  
  20.   
  21.     abstract String sale();  
  22. }  
  23.   
  24. /* 具體實現部分 */  
  25. class BeefSteak extends Steak{  
  26.     BeefSteak(Rations rations) { super(rations); }  
  27.   
  28.     @Override public String sale() { return "牛扒"+ (rations == null ? "" : rations.rations()); }  
  29. }  
  30.   
  31. class PorkSteak extends Steak {  
  32.     PorkSteak(Rations rations) { super(rations); }  
  33.   
  34.     @Override public String sale() { return "豬扒"+ (rations == null ? "" : rations.rations()); }  
  35. }  
  36.   
  37.   
  38. /* 客戶端調用 */  
  39. public class Restaurant {  
  40.     public static void main(String[] args) {  
  41.         System.out.println("\n" + new Date(System.currentTimeMillis()));  
  42.         System.out.println("==================");  
  43.   
  44.         Steak steak1 = new BeefSteak(new Rice());  
  45.         System.out.println("賣出了一份:" + steak1.sale());  
  46.   
  47.         Steak steak2 = new PorkSteak(new Spaghetti());  
  48.         System.out.println("賣出了一份:" + steak2.sale());  
  49.   
  50.         Steak steak3 = new PorkSteak(null);  
  51.         System.out.println("賣出了一份:" + steak3.sale());  
  52.   
  53.          System.out.println("==================");  

輸出結果


十一.外觀模式(Facade Pattern)

要求一個子系統的外部與内部的通信必須通過一個統一的對象進行,外觀模式提供一個高層次的接口,使得子系統更易于使用。(其實就是封裝,用于解決類與類間的依賴關系,比如本來是:玩家依賴于:Q,A,E,R等鍵位對象,現在變成隻依賴與腳本對象從而降低了類間的耦合度。)

代碼示例

Java代碼
  1. /* 子系統 */  
  2. class A {  
  3.     String a() { return "A"; }  
  4. }  
  5.   
  6. class Q { /* ... */ }  
  7.   
  8. class Space { /* ... */ }  
  9.   
  10. class LeftClick { /* ... */ }  
  11.   
  12. /* 外觀類 */  
  13. class JiaoBen {  
  14.     A a;  
  15.     Q q;  
  16.     LeftClick leftClick;  
  17.     Space space;  
  18.   
  19.     JiaoBen() {  
  20.         a = new A();  
  21.         leftClick = new LeftClick();  
  22.         q = new Q();  
  23.         space = new Space();  
  24.     }  
  25.   
  26.     String 銳雯() {  
  27.         StringBuilder sb = new StringBuilder();  
  28.         sb.append(q.q()).append(" + ");  
  29.         sb.append(space.space()).append(" + ");  
  30.         sb.append(a.a()).append(" + ");  
  31.         sb.append(leftClick.leftClick()).append(" + ");  
  32.         sb.append(q.q()).append(" + ");  
  33.         sb.append(space.space()).append(" + ");  
  34.         sb.append(a.a()).append(" + ");  
  35.         sb.append(leftClick.leftClick()).append(" + ");  
  36.         sb.append(q.q()).append(" + ");  
  37.         sb.append(space.space()).append(" + ");  
  38.         sb.append(a.a()).append(" + ");  
  39.         sb.append(leftClick.leftClick()).append("\n");  
  40.         return sb.toString();  
  41.     }  
  42. }  
  43.   
  44. /* 客戶端調用 */  
  45. public class XLoLer {  
  46.     public static void main(String[] args) {  
  47.         JiaoBen jiaoBen = new JiaoBen();  
  48.         System.out.println("=== 銳雯一鍵光速QA ===\n" + jiaoBen.銳雯());  
  49.     }  
  50. }

輸出結果


十二. 享元模式(Flyweight Pattern)

當存在多個相同對象時,可以使用享元模式減少相同對象創建引起的内存消耗,提高程序性能。說到共享,還分内部狀态與外部狀态

内部狀态固定不變可共享的的部分,存儲在享元對象内部,比如例子中的花色
外部狀态可變不可共享的部分,一般由客戶端傳入享元對象内部,比如例子裡的大小

示例代碼

Java代碼
  1. /* 抽象對象的父類 */  
  2. abstract class Card {  
  3.     abstract void showCard(String num);  //傳入外部狀态參數,大小  
  4. }  
  5.   
  6. /* 具體享元對象 */  
  7. public class SpadeCard extends Card{  
  8.     public SpadeCard() { super(); }  
  9.   
  10.     @Override public void showCard(String num) { System.out.println("黑桃:" + num); }  
  11. }  
  12.   
  13. public class HeartCard extends Card { /* ... */ }  
  14.   
  15. public class ClubCard extends Card { /* ... */ }  
  16.   
  17. public class DiamondCard extends Card { /* ... */ }  
  18.   
  19. /* 享元工廠 */  
  20. public class PokerFactory {  
  21.     static final int Spade = 0;  //黑桃  
  22.     static final int Heart  = 1//紅桃  
  23.     static final int Club  = 2//梅花  
  24.     static final int Diamond  = 3;   //方塊  
  25.   
  26.     public static Map<Integer, Card> pokers = new HashMap<>();  
  27.   
  28.     public static Card getPoker(int color) {  
  29.         if (pokers.containsKey(color)) {  
  30.             System.out.print("對象已存在,對象複用...");  
  31.             return pokers.get(color);  
  32.         } else {  
  33.             System.out.print("對象不存在,新建對象...");  
  34.             Card card;  
  35.             switch (color) {  
  36.                 case Spade: card = new SpadeCard(); break;  
  37.                 case Heart: card = new HeartCard(); break;  
  38.                 case Club: card = new ClubCard(); break;  
  39.                 case Diamond: card = new DiamondCard(); break;  
  40.                 default: card = new SpadeCard(); break;  
  41.             }  
  42.             pokers.put(color,card);  
  43.             return card;  
  44.         }  
  45.     }  
  46.   
  47.   
  48. /* 客戶端調用 */  
  49. public class Player {  
  50.     public static void main(String[] args) {  
  51.         for (int k = 0; k < 10; k ++){  
  52.             Card card = null;  
  53.             //随機花色  
  54.             switch ((int)(Math.random()*4)) {  
  55.                 case 0: card = PokerFactory.getPoker(PokerFactory.Spade); break;  
  56.                 case 1: card = PokerFactory.getPoker(PokerFactory.Heart); break;  
  57.                 case 2: card = PokerFactory.getPoker(PokerFactory.Club); break;  
  58.                 case 3: card = PokerFactory.getPoker(PokerFactory.Diamond); break;  
  59.             }  
  60.             if(card != null) {  
  61.                 //随機大小  
  62.                 int num = (int)(Math.random()*13 + 1);  
  63.                 switch (num) {  
  64.                     case 11: card.showCard("J"); break;  
  65.                     case 12: card.showCard("Q"); break;  
  66.                     case 13: card.showCard("K"); break;  
  67.                     default: card.showCard(num+""); break;  
  68.                 }  
  69.             }  
  70.         }  
  71.     }  

輸出結果


十三.代理模式(Proxy Pattern)

引用代理對象的方式來訪問目标對象,簡單點說,就是在調用某個對象時加了一層,然後你可以在這一層做些手腳,比如權限控制,或者附加操作等。

代碼示例

Java代碼
  1. /* 抽象對象 */  
  2. public interface FetchGoods {  
  3.     public void fetchShoes();  
  4. }  
  5.   
  6. /* 真實對象 */  
  7. public class Custom implements FetchGoods{  
  8.     @Override public void fetchShoes() { System.out.println("拿貨"); }  
  9. }  
  10.   
  11. /* 代理對象 */  
  12. public class Agent implements FetchGoods{  
  13.     @Override public void fetchShoes() {  
  14.         Custom custom = new Custom();  
  15.         custom.fetchShoes();  
  16.         this.callCustom();  
  17.     }  
  18.   
  19.     public void callCustom() { System.out.println("通知顧客過來取件!"); }  
  20. }  
  21.   
  22. /* 客戶端調用 */  
  23. public class Client {  
  24.     public static void main(String[] args) {  
  25.         Agent agent = new Agent();  
  26.         agent.fetchShoes();  
  27.     }  

輸出結果


十四.策略模式(Strategy Pattern)

定義一系列的算法,把每個算法封裝起來,并使得他們可以相互替換讓算法獨立于使用它的客戶而變化。 一般用來替換if-else,個人感覺是面向過程與面向對象思想的過渡。

代碼示例:(面向過程與面向對象的簡易計算器)

面向過程簡易計算器

Java代碼
  1. public class Calculator {  
  2.     public static void main(String[] args) {  
  3.         System.out.println("計算:1 + 1 = " + compute("+"11));  
  4.         System.out.println("計算:1 - 1 = " + compute("-"11));  
  5.         System.out.println("計算:1 * 1 = " + compute("*"11));  
  6.         System.out.println("計算:1 ? 1 = " + compute("/"11));  
  7.     }  
  8.   
  9.     public static float compute(String operator, int first, int second) {  
  10.         switch (operator) {  
  11.             case "+"return first + second;  
  12.             case "-"return first - second;  
  13.             case "*"return first * second;  
  14.             case "/"return first / second;  
  15.             defaultreturn 0.0f;  
  16.         }  
  17.     }  
  18. }

面向對象(策略模式)簡易計算器

Java代碼
  1. /* 抽象策略類 */  
  2. public interface Compute {  
  3.     String compute(int first, int second);  
  4. }  
  5.   
  6. /* 具體策略類 */  
  7. public class Add implements Compute{  
  8.     @Override public String compute(int first, int second) {  
  9.         return "輸出結果:" + first + " + " + second + " = " + (first + second);  
  10.     }  
  11. }  
  12.   
  13. public class Sub implements Compute{ /* ... */ }  
  14.   
  15. public class Mul implements Compute{ /* ... */ }  
  16.   
  17. public class Div implements Compute{ /* ... */ }  
  18.   
  19. /* 上下文環境類 */  
  20. public class Context {  
  21.     private Compute compute;  
  22.   
  23.     public Context() { compute = new Add(); }  
  24.   
  25.     public void setCompute(Compute compute) { this.compute = compute; }  
  26.   
  27.     public void calc(int first, int second) {   
  28.         System.out.println(compute.compute(first, second));   
  29.     }  
  30. }  
  31.   
  32. /* 客戶端調用 */  
  33. public class Client {  
  34.     public static void main(String[] args) {  
  35.         Context context = new Context();  
  36.   
  37.         context.setCompute(new Add());  
  38.         context.calc(1,2);  
  39.   
  40.         context.setCompute(new Sub());  
  41.         context.calc(3,4);  
  42.   
  43.         context.setCompute(new Mul());  
  44.         context.calc(5,6);  
  45.   
  46.         context.setCompute(new Div());  
  47.         context.calc(7,8);  
  48.     }  
  49. }  

輸出結果

      


十五.觀察者模式(Observer Pattern)

定義對象見的一種一對多依賴關系,當一個對象的狀态發生改變時,所有依賴于它的對象都得到通知并且自動更新

當對象間存在一對多關系的時候,使用觀察者模式,當一個對象(被觀察者)被修改時,會自動通知它的依賴對象們(觀察者)。

這個模式基本都應該用過和聽說過,關于概念就不多解釋了,有興趣看原文去~

代碼示例

Java代碼
  1. /* 抽象觀察者 —— 昆蟲類 */  
  2. public interface Insect {  
  3.     void work();  
  4.     void unWork();  
  5. }  
  6.   
  7. /* 具體觀察者 —— 蜜蜂類 */  
  8. public class Bee implements Insect{  
  9.     private int bId;    //蜜蜂編号  
  10.     public Bee(int bId) { this.bId = bId; }  
  11.     @Override public void work() { System.out.println("蜜蜂"+ bId + "采蜜"); }  
  12.     @Override public void unWork() { System.out.println("蜜蜂"+ bId + "回巢"); }  
  13. }  
  14.   
  15. /* 抽象被觀察者(注冊,移除,通知觀察者) —— 植物類 */  
  16. public interface Plant {  
  17.     public void registerInsect(Insect insect);  
  18.     public void unregisterInsect(Insect insect);  
  19.     public void notifyInsect(boolean isOpen);  
  20. }  
  21.   
  22. /* 具體被觀察者(定義一個集合存儲觀察者,實現相關方法) —— 花朵類 */  
  23. public class Flower implements Plant {  
  24.     private boolean state;  
  25.     private List<Insect> insects = new ArrayList<>();  
  26.     public boolean isState() { return state; }  
  27.   
  28.     @Override public void registerInsect(Insect insect) { insects.add(insect); }  
  29.     @Override public void unregisterInsect(Insect insect) { insects.remove(insect); }  
  30.     @Override public void notifyInsect(boolean isOpen) {  
  31.         state = isOpen;  
  32.         if (state) {  
  33.             System.out.println("花開");  
  34.             for (Insect insect : insects) { insect.work(); }  
  35.         } else {  
  36.             System.out.println("花閉");  
  37.             for (Insect insect : insects) { insect.unWork(); }  
  38.         }  
  39.     }  
  40. }  
  41.   
  42. /* 客戶端調用 */  
  43. public class Client {  
  44.     public static void main(String[] args) {  
  45.         //創建被觀察者  
  46.         Plant flower = new Flower();  
  47.         //創建三個觀察者  
  48.         Insect bee1 = new Bee(1);  
  49.         Insect bee2 = new Bee(2);  
  50.         Insect bee3 = new Bee(3);  
  51.         //注冊觀察者  
  52.         flower.registerInsect(bee1);  
  53.         flower.registerInsect(bee2);  
  54.         flower.registerInsect(bee3);  
  55.         //改變被觀察者狀态,先開後合  
  56.         flower.notifyInsect(true);  
  57.         System.out.println("=== 太陽從東邊到西邊... ===");  
  58.         flower.notifyInsect(false);  
  59.         //最後解除注冊  
  60.         flower.unregisterInsect(bee1);  
  61.         flower.unregisterInsect(bee2);  
  62.         flower.unregisterInsect(bee3);  
  63.     }  
  64. }

輸出結果


觀察者模式的推與拉

推方式

被觀察者對象向觀察者推送主題的詳細信息,不管觀察者是否需要,推送的信息通常是被觀察者對象的全部或部分數據。(上面的例子就是推方式)

拉方式

被觀察者對象再通知觀察者時,隻傳遞少量信息。如果觀察者需要更詳細的信息,可以主動到被觀察者中獲取,相當于觀察者從被觀察者中拉取數據。一般的套路是:**把主題對象自身通過update()方法傳遞給觀察者,然後觀察者在需要獲取的時候,通過這個引用來獲取**。

代碼示例

微信訂閱了某個公衆号,當有更新的時候會推送提醒,收到提醒後,我們需要進入公衆号然後點擊對應信息查看詳細内容。

Java代碼
  1. /* 抽象觀察者 —— 用戶 */  
  2. public interface User {  
  3.     public void update(OfficialAccount account);  
  4. }  
  5.   
  6. /* 具體觀察者 —— Android讀者 */  
  7. public class AndroidDev implements User {  
  8.     @Override public void update(OfficialAccount account) {  
  9.         System.out.println("讀者查看公衆号更新信息:" +  ((CoderPig)account).getMsg());  
  10.     }  
  11. }  
  12.   
  13. /* 抽象被觀察者 —— 公衆号 */  
  14. public abstract class OfficialAccount {  
  15.     private List<User> userList = new ArrayList<>();  
  16.     public void registerUser(User user) { userList.add(user); }  
  17.     public void unregisterUser(User user) { userList.remove(user); }  
  18.     public void notifyUse() {  
  19.         for (User user: userList) {  
  20.             user.update(this);  
  21.         }  
  22.     }  
  23. }  
  24.   
  25. /* 具體被觀察者 —— CoderPig公衆号 */  
  26. public class CoderPig extends OfficialAccount {  
  27.     private String msg; //更新的文章  
  28.     public String getMsg() { return msg; }  
  29.     public void update(String msg) {  
  30.         this.msg = msg;  
  31.         System.out.println("公衆号更新了文章:" + msg);  
  32.         this.notifyUse();   //通知用戶有更新  
  33.     }  
  34. }  
  35.   
  36. /* 客戶端調用 */  
  37. public class Client {  
  38.     public static void main(String[] args) {  
  39.         OfficialAccount account = new CoderPig();  
  40.         User user = new AndroidDev();  
  41.         account.registerUser(user);  
  42.         ((CoderPig)account).update("《觀察者模式》");  
  43.         account.unregisterUser(user);  
  44.     }  

輸出結果


Java中對觀察者模式的支持(在Java.util中)

口訣被觀察者實現繼承Observable觀察者實現Observer接口,然後有個很關鍵的地方:當通知變化的時候,需要調用setChange()方法!!!! 不用自己另外去寫抽象觀察者或抽象被觀察者類,直接繼承就能玩了,另外有一點要注意的是:Java内置的觀察者模式通知多個觀察者的順序不是固定的,如果對通知順序有所依賴的話,還是得自己實現觀察者模式!

代碼示例

Java代碼
  1. /* 具體觀察者 */  
  2. public class AndroidDev implements Observer{  
  3.     @Override public void update(Observable o, Object object) {  
  4.         System.out.println("收到公衆号更新信息:" + object);  
  5.     }  
  6. }  
  7.   
  8. /* 具體被觀察者 */  
  9. public class CoderPig extends Observable {  
  10.     private String msg;  
  11.     public String getMsg() { return msg; }  
  12.   
  13.     public void update(String msg) {  
  14.         this.msg = msg;  
  15.         System.out.println("公衆号更新了文章:" + msg);  
  16.         this.setChanged();  //這句話必不可少,通知改變  
  17.         this.notifyObservers(this.msg); //這裡用推的方式  
  18.     }  
  19. }  
  20.   
  21. /* 客戶端調用 */  
  22. public class Client {  
  23.     public static void main(String[] args) {  
  24.         CoderPig coderPig = new CoderPig();  
  25.         AndroidDev dev = new AndroidDev();  
  26.         coderPig.addObserver(dev);  
  27.         coderPig.update("Java中對觀察者模式的支持~");  
  28.         coderPig.deleteObserver(dev);  
  29.     }  
  30. }

輸出結果


十六.疊代器模式(Iterator Pattern)

提供一種方法順序訪問一個容器(聚合)對象各個元素,而又不暴露該對象的内部表示

從上面的定義可以知道,這個模式的使用場景:容器對象中的元素疊代訪問

四個角色

UML類圖

代碼示例

Java代碼
  1. /* 集合中的元素 */  
  2. public class Song {  
  3.     private String name;  
  4.     private String singer;  
  5.     public Song(String name, String singer) {  
  6.         this.name = name;  
  7.         this.singer = singer;  
  8.     }  
  9.   
  10.     /* getter和setter方法 */  
  11.   
  12.     @Override public String toString() {   
  13.         return "【歌名】" + name + " - " + singer;   
  14.     }  
  15. }  
  16.   
  17. /* 疊代器角色,第一項,下一個,判斷是否能下一個,獲取當前項。 */  
  18. public interface Iterator {  
  19.     Song first();  
  20.     Song next();  
  21.     boolean hashNext();  
  22.     Song currentItem();  
  23. }  
  24.   
  25. /* 抽象容器,定義一個生成疊代器的方法 */  
  26. interface SongList {  
  27.     Iterator getIterator();  
  28. }  
  29.   
  30. /* 具體容器,繼承抽象容器,并定義一個具體疊代器内部類 */  
  31. public class MyStoryList implements SongList{  
  32.     private List<Song> list = new ArrayList<>();  
  33.   
  34.     public MyStoryList(List<Song> list) {  
  35.         this.list = list;  
  36.     }  
  37.   
  38.     @Override public Iterator getIterator() {  
  39.         return new SongListIterator();  
  40.     }  
  41.   
  42.     private class SongListIterator implements Iterator {  
  43.         private int cursor;  
  44.   
  45.         @Override public Song first() {  
  46.             cursor = 0;  
  47.             return list.get(cursor);  
  48.         }  
  49.   
  50.         @Override public Song next() {  
  51.             Song song = null;  
  52.             cursor++;  
  53.             if(hashNext()) {  
  54.                 song = list.get(cursor);  
  55.             }  
  56.             return song;  
  57.         }  
  58.   
  59.         @Override public boolean hashNext() {  
  60.             return !(cursor == list.size());  
  61.         }  
  62.   
  63.         @Override public Song currentItem() {  
  64.             return list.get(cursor);  
  65.         }  
  66.     }  
  67. }  
  68.   
  69. /* 客戶端調用 */  
  70. public class Client {  
  71.     public static void main(String[] args) {  
  72.         List<Song> list = new ArrayList<>();  
  73.         list.add(new Song("空白格","楊宗緯"));  
  74.         list.add(new Song("那時候的我","劉惜君"));  
  75.         list.add(new Song("黑澤明","陳奕迅"));  
  76.         list.add(new Song("今天隻做一件事","陳奕迅"));  
  77.         list.add(new Song("童話鎮","陳一發兒"));  
  78.   
  79.         MyStoryList songList = new MyStoryList(list);  
  80.   
  81.         Iterator iterator = songList.getIterator();  
  82.   
  83.         while (iterator.hashNext()) {  
  84.             System.out.println(iterator.currentItem().toString());  
  85.             iterator.next();  
  86.         }  
  87.     }  
  88. }

輸出結果

PS:由于容器與疊代器的關系太密切了,所以大多數語言在實現容器的時候都給提供了疊代器,并且這些語言提供的容器和疊代器在絕大多數情況下就可以滿足我們的需要,所以現在需要我們自己去實踐疊代器模式的場景還是比較少見的,我們隻需要使用語言中已有的容器和疊代器就可以了。


十七.命令模式(Command Pattern)

使用場景行為請求者行為實現者解耦

定義:将一個請求封裝成一個對象,從而可用不同的請求對客戶端參數化,對請求排隊或記錄請求日志,以及支持可撤銷的操作。

代碼示例

Java代碼
  1. /* 元素對象  */  
  2. public class Story {  
  3.     private String sName;  
  4.     private String sUrl;  
  5.   
  6.     public Story(String sName, String sUrl) {  
  7.         this.sName = sName;  
  8.         this.sUrl = sUrl;  
  9.     }  
  10.   
  11.     /*getter和setter方法*/  
  12. }  
  13.   
  14. /* 命令執行者 */  
  15. public class StoryPlayer {  
  16.     private int cursor = 0//當前播放項  
  17.     private int pauseCursor = -1;   //暫停播放項  
  18.     private List<Story> playList = new ArrayList<>();   //播放列表  
  19.   
  20.     public void setPlayList(List<Story> list) {  
  21.         this.playList = list;  
  22.         cursor = 0;  
  23.         System.out.println("更新播放列表...");  
  24.     }  
  25.   
  26.     public void play() { /* 播放 */ }  
  27.     public void play(int cursor) { /* 根據遊标播放 */ }  
  28.     public void next() { /* 下一首 */ }  
  29.     public void pre() { /* 上一首 */ }  
  30.     public void pause() { /* 暫停 */ }  
  31.   
  32. }  
  33.   
  34. /* 抽象命令接口 */  
  35. public interface Command { void execute(); }  
  36.   
  37. /* 具體命令類 */  
  38. public class SetListCommand implements Command {  
  39.     private StoryPlayer mPlayer;  
  40.     private List<Story> mList = new ArrayList<>();  
  41.   
  42.     public SetListCommand(StoryPlayer mPlayer) { this.mPlayer = mPlayer; }  
  43.   
  44.     @Override public void execute() { mPlayer.setPlayList(mList); }  
  45.   
  46.     public void setPlayList(List<Story> list) { this.mList = list; }  
  47. }  
  48.   
  49. public class PlayCommand implements Command {  
  50.     private StoryPlayer mPlayer;  
  51.   
  52.     public PlayCommand(StoryPlayer mPlayer) { this.mPlayer = mPlayer; }  
  53.   
  54.     @Override public void execute() { mPlayer.play(); }  
  55. }  
  56.   
  57. public class PlayCommand implements Command { /* ... */ }  
  58.   
  59. public class PauseCommand implements Command { /* ... */ }  
  60.   
  61. public class NextCommand implements Command { /* ... */ }  
  62.   
  63. public class PreCommand implements Command { /* ... */ }  
  64.   
  65.   
  66. /* 請求者類,調用命令對象執行具體操作 */  
  67. public class Invoker {  
  68.     private SetListCommand setListCommand;  
  69.     private PlayCommand playCommand;  
  70.     private PauseCommand pauseCommand;  
  71.     private NextCommand nextCommand;  
  72.     private PreCommand preCommand;  
  73.   
  74.     public void setSetListCommand(SetListCommand setListCommand) {  
  75.         this.setListCommand = setListCommand;  
  76.     }  
  77.   
  78.     public void setPlayCommand(PlayCommand playCommand) {  
  79.         this.playCommand = playCommand;  
  80.     }  
  81.   
  82.     public void setPauseCommand(PauseCommand pauseCommand) {  
  83.         this.pauseCommand = pauseCommand;  
  84.     }  
  85.   
  86.     public void setNextCommand(NextCommand nextCommand) {  
  87.         this.nextCommand = nextCommand;  
  88.     }  
  89.   
  90.     public void setPreCommand(PreCommand preCommand) {  
  91.         this.preCommand = preCommand;  
  92.     }  
  93.   
  94.     /* 設置播放列表 */  
  95.     public void setPlayList(List<Story> list) {   
  96.         setListCommand.setPlayList(list);  
  97.         setListCommand.execute();  
  98.     }  
  99.     public void play() { playCommand.execute(); } /* 播放 */  
  100.     public void pause() { pauseCommand.execute(); } /* 暫停 */  
  101.     public void next() { nextCommand.execute(); }   /* 下一首 */  
  102.     public void pre() { preCommand.execute(); }    /* 上一首 */  
  103. }  
  104.   
  105. /* 客戶端調用 */  
  106. public class Client {  
  107.     public static void main(String[] args) {  
  108.         //實例化播放列表  
  109.         List<Story> mList = new ArrayList<>();  
  110.         mList.add(new Story("白雪公主",""));  
  111.         mList.add(new Story("青蛙的願望",""));  
  112.         mList.add(new Story("驢和媽",""));  
  113.         mList.add(new Story("小青蛙的煩惱",""));  
  114.         mList.add(new Story("三字經",""));  
  115.   
  116.         //實例化接收者  
  117.         StoryPlayer mPlayer = new StoryPlayer();  
  118.   
  119.         //實例化命令對象  
  120.         Command setListCommand = new SetListCommand(mPlayer);  
  121.         Command playCommand = new PlayCommand(mPlayer);  
  122.         Command pauseCommand = new PauseCommand(mPlayer);  
  123.         Command nextCommand = new NextCommand(mPlayer);  
  124.         Command preCommand = new PreCommand(mPlayer);  
  125.   
  126.         //實例化請求者  
  127.         Invoker invoker = new Invoker();  
  128.         invoker.setSetListCommand((SetListCommand) setListCommand);  
  129.         invoker.setPlayList(mList);  
  130.         invoker.setPlayCommand((PlayCommand) playCommand);  
  131.         invoker.setPauseCommand((PauseCommand) pauseCommand);  
  132.         invoker.setNextCommand((NextCommand) nextCommand);  
  133.         invoker.setPreCommand((PreCommand) preCommand);  
  134.   
  135.         //測試調用  
  136.         invoker.play();  
  137.         invoker.next();  
  138.         invoker.next();  
  139.         invoker.next();  
  140.         invoker.next();  
  141.         invoker.next();  
  142.         invoker.pause();  
  143.         invoker.play();  
  144.     }  
  145. }

輸出結果


十八.備忘錄模式(Memento Pattern)

簡單點說,就是存檔保存一個對象在某個時刻的狀态或部分狀态在未來某個時段需要時将其還原到原來記錄狀态的模式

代碼示例

Java代碼
  1. /* 備忘錄角色 —— 存檔類*/  
  2. public class Memento {  
  3.     private int hp;  
  4.     private int mp;  
  5.     private int money;  
  6.   
  7.     public Memento(int hp, int mp, int money) {  
  8.         this.hp = hp;  
  9.         this.mp = mp;  
  10.         this.money = money;  
  11.     }  
  12.   
  13.     /*getter和setter方法*/  
  14. }  
  15.   
  16. /* 發起人角色 —— 角色類,屬性定義,定義保存與恢複自身狀态的方法 */  
  17. public class Character {  
  18.     private int hp;  
  19.     private int mp;  
  20.     private int money;  
  21.   
  22.     public Character(int hp, int mp, int money) {  
  23.         this.hp = hp;  
  24.         this.mp = mp;  
  25.         this.money = money;  
  26.     }  
  27.   
  28.     /*getter和setter方法*/  
  29.   
  30.     public void showMsg() {  
  31.         System.out.println("當前狀态:| HP:" + hp + " | MP:" + mp + " | 金錢:" + money + "\n");  
  32.     }  
  33.   
  34.     //創建一個備忘錄,保存當前自身狀态  
  35.     public Memento save() { return new Memento(hp, mp, money); }  
  36.   
  37.     //傳入一個備忘錄對象,恢複内部狀态  
  38.     public void restore(Memento memento) {  
  39.         this.hp = memento.getHp();  
  40.         this.mp = memento.getMp();  
  41.         this.money = memento.getMoney();  
  42.     }  
  43. }  
  44.   
  45. /* 備忘錄管理者角色 —— 隻負責備忘錄對象的傳遞! 多個存檔的話可用集合存,根據索引取*/  
  46. public class Caretaker {  
  47.     private Memento memento;  
  48.   
  49.     public Memento getMemento() { return memento; }  
  50.   
  51.     public void setMemento(Memento memento) { this.memento = memento; }  
  52. }  
  53.   
  54. /* 客戶端調用 */  
  55. public class Client {  
  56.     public static void main(String[] args) {  
  57.         Caretaker caretaker= new Caretaker();  
  58.         Character character = new Character(2000,1000,500);  
  59.         //存檔  
  60.         System.out.println("=== 存檔中... ===");  
  61.         character.showMsg();  
  62.         caretaker.setMemento(character.save());  
  63.   
  64.         System.out.println("=== 單挑Boss,不敵,金錢扣除一半... ===");  
  65.         character.setHp(0);  
  66.         character.setHp(0);  
  67.         character.setHp(250);  
  68.         character.showMsg();  
  69.   
  70.         //讀檔  
  71.         System.out.println("=== 讀取存檔中... ===");  
  72.         character.restore(caretaker.getMemento());  
  73.         character.showMsg();  
  74.     }  
  75. }

十九.中介者模式(Mediator Pattern)

用一個中介對象來封裝一系列的對象交互,使得各對象不需要顯式的相互引用, 從而使其耦合松散,而且可以獨立的改變他們之間的交互。

中介者持有所有同事引用,然後在裡面做一些邏輯操作,然後每個同事類持有中介者引用,依次完成交互。

這裡的話需要與前面的外觀模式,代理模式進行區分!

外觀模式結構型,對子系統提供統一的接口,單向,所有請求都委托子系統完成,樹型
代理模式結構型引用代理對象的方式來訪問目标對象單向
中介者模式行為型,用一個中介對象封裝一系列同事對象的交互行為雙向一對多星型

UML類圖

代碼示例

Java代碼
  1. /* 抽象中介類,有連接同事進行交互的方法*/  
  2. public abstract class Mediator {  
  3.     abstract void contact(People people, String msg);  
  4. }  
  5.   
  6. /* 抽象同事類,相關屬性,還有一個中介類的引用,因為所有同事都知道中介*/  
  7. public abstract class People {  
  8.     protected String name;  
  9.     protected Mediator mediator;    //每個人都知道中介  
  10.   
  11.     public People(String name, Mediator mediator) {  
  12.         this.name = name;  
  13.         this.mediator = mediator;  
  14.     }  
  15. }  
  16.   
  17. /* 具體同事類,這裡是房東和房客*/  
  18. public class Landlord extends People {  
  19.     public Landlord(String name, Mediator mediator) { super(name, mediator); }  
  20.   
  21.     public void contact(String msg) { mediator.contact(this, msg); }  
  22.   
  23.     public void getMessage(String msg) { System.out.println("【房東】" + name + ":" + msg); }  
  24. }  
  25.   
  26. public class Tenant extends People {  
  27.     public Tenant(String name, Mediator mediator) { super(name, mediator); }  
  28.   
  29.     public void contact(String msg) { mediator.contact(this, msg); }  
  30.   
  31.     public void getMessage(String msg) { System.out.println("【房客】" + name + ":" + msg); }  
  32. }  
  33.   
  34. /* 具體中介類,中介者知道所有的同事,實現交互方法時對調用者進行判斷 
  35.  實現對應的邏輯,比如這裡的信息顯示*/  
  36. public class HouseMediator extends Mediator {  
  37.     //中介者知道所有同事  
  38.     private Landlord landlord;  
  39.     private Tenant tenant;  
  40.   
  41.     public Landlord getLandlord() { return landlord; }  
  42.     public void setLandlord(Landlord landlord) { this.landlord = landlord; }  
  43.     public Tenant getTenant() { return tenant; }  
  44.     public void setTenant(Tenant tenant) { this.tenant = tenant; }  
  45.   
  46.     @Override void contact(People people, String msg) {  
  47.         if(people == tenant) tenant.getMessage(msg);  
  48.         else landlord.getMessage(msg);  
  49.     }  
  50. }  
  51.   
  52. /* 客戶端調用 */  
  53. public class Client {  
  54.     public static void main(String[] args) {  
  55.         //實例化中介者  
  56.         HouseMediator mediator = new HouseMediator();  
  57.         //實例化同事對象,傳入中介者實例  
  58.         Landlord landlord = new Landlord("包租婆",mediator);  
  59.         Tenant tenant = new Tenant("小豬",mediator);  
  60.         //為中介者傳入同事實例  
  61.         mediator.setLandlord(landlord);  
  62.         mediator.setTenant(tenant);  
  63.         //調用  
  64.         landlord.contact("單間500一個月,有興趣嗎?");  
  65.         tenant.contact("熱水器,空調,網線有嗎?");  
  66.         landlord.contact("都有。");  
  67.         tenant.contact("好吧,我租了。");  
  68.     }  
  69. }

輸出結果


二十.解釋器模式(Interpreter Pattern)

用得比較少的一種模式,定義也比較枯澀難懂,實在不理解可以先看代碼:

給定一個語言之後,解釋器模式可以定義出其文法的一種表示,并同時提供一個解釋器,客戶端可以使用這個解釋器來解釋這個語言中的句子。

個人理解

定義了一套簡單語法,每個終結符有一個對應的值存起來了,然後當你輸了一串終結符,最後解釋能得出一個正确結果

代碼示例能夠解釋加減法的解釋器

Java代碼
  1. /* 抽象表達式 */  
  2. public abstract class Expression {  
  3.     public abstract int interpret(Context context);  
  4.     @Override public abstract String toString();  
  5. }  
  6.   
  7. /* 非終結符表達式 —— 加法和減法 */  
  8. public class PlusExpression extends Expression{  
  9.     private Expression leftExpression;  
  10.     private Expression rightExpression;  
  11.   
  12.     public PlusExpression(Expression leftExpression, Expression rightExpression) {  
  13.         this.leftExpression = leftExpression;  
  14.         this.rightExpression = rightExpression;  
  15.     }  
  16.   
  17.     @Override public int interpret(Context context) {  
  18.         return leftExpression.interpret(context) + rightExpression.interpret(context);  
  19.     }  
  20.   
  21.     @Override public String toString() {  
  22.         return leftExpression.toString() + " + " + rightExpression.toString();  
  23.     }  
  24. }  
  25.   
  26. public class MinusExpression extends Expression{ /* 和減法類似 */ }  
  27.   
  28. /* 終結符表達式 —— 常量與變量*/  
  29. public class ConstantExpression extends Expression {  
  30.     private int value;  
  31.   
  32.     public ConstantExpression(int value) { this.value = value; }  
  33.   
  34.     @Override public int interpret(Context context) { return value; }  
  35.   
  36.     @Override public String toString() { return Integer.toString(value); }  
  37. }  
  38.   
  39. public class VariableExpression extends Expression {  
  40.     private String name;  
  41.   
  42.     public VariableExpression(String name) { this.name = name; }  
  43.   
  44.     @Override public int interpret(Context context) { return context.lookup(this); }  
  45.   
  46.     @Override public String toString() { return name; }  
  47. }  
  48.   
  49. /* 上下文環境 —— 用Map存放各個終結符對應的具體值*/  
  50. public class Context {  
  51.     private Map<Expression, Integer> map = new HashMap<>();  
  52.   
  53.     public void addExpression(Expression expression, int value) { map.put(expression, value); }  
  54.   
  55.     public int lookup(Expression expression) { return map.get(expression); }  
  56. }  
  57.   
  58. /* 客戶端調用 */  
  59. public class Client {  
  60.     public static void main(String[] args) {  
  61.         Context context = new Context();  
  62.   
  63.         VariableExpression a = new VariableExpression("a");  
  64.         VariableExpression b = new VariableExpression("b");  
  65.         ConstantExpression c = new ConstantExpression(6);  
  66.   
  67.         context.addExpression(a, 2);  
  68.         context.addExpression(b, 3);  
  69.   
  70.         Expression expression = new PlusExpression(new PlusExpression(a,b),new MinusExpression(a,c));  
  71.         System.out.println(expression.toString() + " = " + expression.interpret(context));  
  72.     }  
  73. }

輸出結果


二十一.訪問者模式(Visitor Pattern)

核心數據結構不變操作可變,結構與操作解耦的一種模式。
定義:封裝一些作用域某種數據結構中的個元素的操作,在不改變這個
數據結構的前提下,定義作用于這些元素的新的操作

代碼示例

Java代碼
  1. /* 元素角色 —— 遊戲機接口,有一個傳入訪問者實例的方法 */  
  2. public interface Machine {  
  3.     public void accept(Player player);  
  4. }  
  5.   
  6. /* 具體元素 —— 投籃機,跳舞機和開車 */  
  7. public class Shooting implements Machine {  
  8.     @Override public void accept(Player player) { player.visit(this); }  
  9.     public String feature() { return "投籃機"; }  
  10. }  
  11.   
  12. public class Dancing implements Machine { /*...*/ }  
  13. public class Driving implements Machine { /*...*/ }  
  14.   
  15. /* 抽象訪問者 —— 定義元素對應的訪問方法,傳入相應實例*/  
  16. public interface Player {  
  17.     public void visit(Shooting machine);  
  18.     public void visit(Dancing machine);  
  19.     public void visit(Driving machine);  
  20. }  
  21.   
  22. /* 具體訪問者 —— 男女性玩家 */  
  23. public class MalePlayer implements Player{  
  24.     @Override public void visit(Shooting machine) {   
  25.         System.out.println("男性玩家玩:" + machine.feature());  
  26.     }  
  27.   
  28.     @Override public void visit(Dancing machine) {  
  29.         System.out.println("男性玩家玩:" + machine.feature());  
  30.     }  
  31.   
  32.     @Override public void visit(Driving machine) {  
  33.         System.out.println("男性玩家玩:" + machine.feature());  
  34.     }  
  35. }  
  36.   
  37. public class FemalePlayer implements Player{ /*...*/ }  
  38.   
  39. /* 對象結構 —— 管理元素集合,并且可疊代訪問者訪問 */  
  40. public class GameRoom  {  
  41.     private List<Machine> machines = new ArrayList<>();  
  42.     public void add(Machine machine) { machines.add(machine); }  
  43.     public void action(Player player) {  
  44.         for (Machine machine: machines) { machine.accept(player); }  
  45.     }  
  46. }  
  47.   
  48. /* 客戶端調用 */  
  49. public class Client {  
  50.     public static void main(String[] args) {  
  51.         GameRoom room = new GameRoom();  
  52.         room.add(new Shooting());  
  53.         room.add(new Dancing());  
  54.         room.add(new Driving());  
  55.   
  56.         Player player1 = new MalePlayer();  
  57.         Player player2 = new FemalePlayer();  
  58.   
  59.         room.action(player1);  
  60.         room.action(player2);  
  61.     }  
  62. }

輸出結果


二十二.責任鍊模式(Chain of Responsibility Pattern)

使多個對象都有機會處理請求,從而避免請求的發送者與接收者之間的耦合關系,将這個對象連成一條鍊,并沿着這條鍊傳遞該請求,直到有一個對象處理它為止。(典型代表:Android裡的事件傳遞機制)

代碼示例

Java代碼
  1. /* 抽象處理者 */  
  2. public abstract class Handler {  
  3.     private Handler nextHandler; /* 下家處理者 */  
  4.   
  5.     public Handler getNextHandler() { return  nextHandler; }  
  6.   
  7.     public void setNextHandler(Handler nextHandler) { this.nextHandler = nextHandler; }  
  8.   
  9.     public abstract void handlerRequest(String str, int money);   /* 請求 */  
  10. }  
  11.   
  12. /* 具體處理者 —— 哥哥,爸爸,媽媽,依次傳遞*/  
  13. public class Brother extends Handler {  
  14.     @Override public void handlerRequest(String str, int money) {  
  15.         if(money <= 100) {  
  16.             System.out.println("哥哥:100塊,哥哥還是有的,給你~");  
  17.         } else {  
  18.             if(getNextHandler() != null) {  
  19.                 System.out.println("哥哥:大于100塊,哥哥木有那麼多錢,找粑粑去~");  
  20.                 getNextHandler().handlerRequest(str, money);  
  21.             } else {  
  22.                 System.out.println("哥哥:大于100塊,哥哥木有那麼多錢,粑粑不在家~");  
  23.             }  
  24.         }  
  25.     }  
  26. }  
  27.   
  28. public class Father extends Handler {  
  29.     @Override public void handlerRequest(String str, int money) {  
  30.         if(money <= 500) {  
  31.             System.out.println("粑粑:500塊,粑粑還是有的,給你~");  
  32.         } else {  
  33.             if(getNextHandler() != null) {  
  34.                 System.out.println("粑粑:大于500塊,粑粑木有那麼多錢,找麻麻去~");  
  35.                 getNextHandler().handlerRequest(str, money);  
  36.             } else {  
  37.                 System.out.println("粑粑:大于500塊,粑粑木有那麼多錢,麻麻不在家~");  
  38.             }  
  39.         }  
  40.     }  
  41. }  
  42.   
  43. public class Mother extends Handler {  
  44.     @Override public void handlerRequest(String str, int money) {  
  45.         if(money <= 1000) {  
  46.             System.out.println("麻麻:1000塊,麻麻還是有的,給你~");  
  47.         } else {  
  48.             System.out.println("麻麻:你拿那麼多錢幹嘛?");  
  49.         }  
  50.     }  
  51. }  
  52.   
  53. /* 客戶端調用 */  
  54. public class Client {  
  55.     public static void main(String[] args) {  
  56.         Brother brother = new Brother();  
  57.         Father father = new Father();  
  58.         Mother mother = new Mother();  
  59.   
  60.         //指定下家  
  61.         brother.setNextHandler(father);  
  62.         father.setNextHandler(mother);  
  63.   
  64.         brother.handlerRequest("要錢",1200);  
  65.     }  
  66. }

輸出結果

另外責任鍊模式還分純與不純

  • 純責任鍊,要麼承擔全部責任,要麼責任推個下家,不允許在某處承擔部分或者全部責任,然後又把責任推給下家

  • 不純責任鍊,責任在某處部分或全部被處理後,還向下傳遞。


二十三.狀态模式(State Pattern)

定義:當一個對象的内在狀态發生改變時允許改變其行為,這個對象看起來像是改變了它的類。

套路

抽象出狀态State,然後實現該接口,然後具體化不同狀态,做不同的操作,然後寫一個Context,裡面存儲一個State的實例,然後定義一個可以修改State實例的方法,并在裡面去調用實例的行為方法。

示例代碼

Java代碼
  1. /* 抽象狀态 */  
  2. public interface State {  
  3.     public void doSomeThing();  
  4. }  
  5.   
  6. /* 具體狀态 */  
  7. public class MorningState implements State {  
  8.     @Override public void doSomeThing() { System.out.println("早上賴床!"); }  
  9. }  
  10.   
  11. public class AfternoonState implements State {  
  12.     @Override public void doSomeThing() { System.out.println("下午學習!"); }  
  13. }  
  14.   
  15. public class EveningState implements State {  
  16.     @Override public void doSomeThing() { System.out.println("晚上打球!"); }  
  17. }  
  18.   
  19. /* 上下文環境 */  
  20. public class Context {  
  21.     public void setState(State state) {  
  22.         System.out.println("狀态改變");  
  23.         state.doSomeThing();  
  24.     }  
  25. }  
  26.   
  27. /* 客戶端調用 */  
  28. public class Client {  
  29.     public static void main(String[] args) {  
  30.         MorningState morningState = new MorningState();  
  31.         AfternoonState afternoonState = new AfternoonState();  
  32.         EveningState eveningState = new EveningState();  
  33.   
  34.         Context context = new Context();  
  35.         context.setState(morningState);  
  36.         context.setState(afternoonState);  
  37.         context.setState(eveningState);  
  38.     }  
  39. }

輸出結果


二十四.模闆方法模式(Template Method Pattern)

定義:定義一個操作中的算法的框架,而将一些步驟延遲到子類中,使得子類可以不改變一個算法的結構即可沖定義該算法的某些特定步驟。(定義比較抽象,舉之前工廠模式做奶茶的例子幫助理解下)

奶茶的制作步驟:加奶,加茶,加料,打包

在這幾個步驟中,加奶,加茶,加料這幾步是固定,而打包的話則是不固定的,有些用戶喜歡找個小桌子喝喝奶茶吹吹水,有些喜歡帶回家,存在可變性。

對于這種可變的步驟,可以使用一個叫做鈎子的東西,其實就是一種被聲明在抽象類的方法,可以為空或者默認的實現。鈎子的存在可以讓子類有能力對算法的不同點進行挂鈎,是否需要挂鈎由子類決定。比如例子通過一個标記确定是否需要打包,子類中可以定義一個方法來調用這個方法。

代碼示例

Java代碼
  1. /* 抽象模闆 */  
  2. public abstract class Tea {  
  3.     protected void 加奶() { System.out.println("加入三花淡奶"); }  
  4.     protected abstract void 加茶();  
  5.     protected abstract void 加料();  
  6.     protected  void 打包() { System.out.println("用打包機打包"); }  
  7.   
  8.     protected boolean 是否打包() { return true; }     //鈎子方法  
  9.   
  10.     public final void make() {  
  11.         System.out.println("=== 開始制作 ===");  
  12.         加奶();  
  13.         加茶();  
  14.         加料();  
  15.         if(是否打包()) { 打包(); }  
  16.         System.out.println("=== 制作完畢 ===");  
  17.     }  
  18. }  
  19.   
  20. /* 具體模闆 */  
  21. public class RedTeaMilkTea extends Tea {  
  22.     @Override protected void 加茶() { System.out.println("加入紅茶"); }  
  23.     @Override protected void 加料() { System.out.println("加入珍珠"); }  
  24. }  
  25.   
  26. public class GreenTeaMilkTea extends Tea {  
  27.     private boolean isPack = true;  
  28.     public GreenTeaMilkTea(boolean isPack) { this.isPack = isPack; }  
  29.   
  30.     @Override protected void 加茶() { System.out.println("加入綠茶"); }  
  31.     @Override protected void 加料() { System.out.println("加入椰果"); }  
  32.     @Override protected boolean 是否打包() { return isPack; }  
  33. }  
  34.   
  35. /* 客戶端調用 */  
  36. public class Client {  
  37.     public static void main(String[] args) {  
  38.         Tea tea1 = new RedTeaMilkTea();  
  39.         Tea tea2 = new GreenTeaMilkTea(false);  
  40.   
  41.         tea1.make();  
  42.         System.out.println("");  
  43.         tea2.make();  
  44.     }  
  45. }

輸出結果


To be continue

本節各種設計模式示例代碼下載:http://tnjbk.dnsf85p.top

轉自:簡書

除非特别注明,雞啄米文章均為原創
轉載請标明本文地址:http://dnsf85p.top/software/757.html
2017年8月25日
作者:雞啄米 分類:軟件開發 浏覽: 評論:0