創建型(創建對象): 2 個 (工廠模式, 單例模式)
結構型: 6 個 (適配器模式, 組合模式, 裝飾者模式, 代理模式, 外觀模式, 橋梁模式)
行為型: 8 個 (中介者模式, 策略模式, 模板模式, 觀察者模式, 迭代器模式, 責任鏈模式, 命令模式, 狀態模式)
1. 工廠模式
提供一個創建類的統一接口.
目的: 每次創建類時, 只需要調用這個接口就可以了, 不用每次都需要寫一次創建代碼
上面是簡單的工廠模式, 正常的工廠方法模式, 就是針對每個類, 都要創建一個工廠類. 但是他們可以實現共同的接口. (這種模式映射了之前我看的object c 的那本書), 一般用簡單的工廠模式就可以了.
2. 單例模式
保證在內存中一個類只有一個實例存在, 並且提供一個訪問該實例的全局訪問點.
目的: 例如一個系統中可能存在多個打印任務, 但是只能一個正在工作的打印任務在內存中.
餓漢式: 類加載時, 就創建好了這個單例( 很餓, 所以要立刻吃, 立刻加載)
懶加載(懶漢式): 可以用的時候再加載 (吃的時候再說, 不是一開始就把飯做好)
如果 getInstance() 使用頻率很高, 那肯定是餓漢式好.
利用 反射 破解單例模式
實際上, 在構造器函數內, 加一句話就可以防止反射破解單例
if (instance != null) {
throw new RuntimeException(); // 也就是多次多用構造器時, 拋出異常
}
通過反序列化的方式 構造多個對象, 破解單例
首先,通過序列化把對象寫到硬盤上, 然后在把這個對象反序列化讀回到程序中, 這時就不是之前的對象了.
如何防止序列化, 通過定義一個 readResolve() 方法 , 這個方法的作用是,在反序列化時, 如果這個類已經定義了實例, 直接返回這個實例就可以了, 不需要new一個新的了.
3. 適配器模式
將一個類的接口轉換成客戶希望的另一個接口.
目的: 比如我們去別的地方, 我們的插座的方向頭是不一樣的, 比如(中國, 德國 我出差去德國), 適配器需要滿足以下要求:
(1) 必須符合德國標准的接口,否則的話還是沒辦法插到德國插座中
(2) 在調用上面實現的德標接口進行充電時,提供一種機制,將這個調用轉到對國標接口的調用
這就要求:
(1) 適配器必須實現原有的舊的接口
(2) 適配器對象中持有對新接口的引用,當調用舊接口時,將這個調用委托給實現新接口的對象來處理,也就是在適配器對象中組合一個新接口
4. 組合模式
將對象組合成樹型結構以表示“部分---整體”的層次結構
組合模式類似 “樹”
component: 組合中對象的接口聲明
composite: 樹枝結點(有子節點)
leaf: 樹葉結點(無子節點)
目的: 就是你想要這種層次關系的類時, 就可以使用.
例如: 各部門之間的層級關系

抽象接口類: package com.zyh.designpattern.composite; public abstract class Company { private String name; public Company(String name) { super(); this.name = name; } public Company(){} public String getName() { return name; } public void setName(String name) { this.name = name; } protected abstract void add(Company company); protected abstract void romove(Company company); protected abstract void display(int depth); } 枝結點類: package com.zyh.designpattern.composite; import java.util.ArrayList; import java.util.List; public class ConcreteCompany extends Company { private List cList; public ConcreteCompany() { cList = new ArrayList(); } public ConcreteCompany(String name) { super(name); cList = new ArrayList(); } @Override protected void add(Company company) { // TODO Auto-generated method stub cList.add(company); } @Override protected void display(int depth) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(""); for (int i = 0; i < depth; i++) { sb.append("-"); } System.out.println(new String(sb) + this.getName()); for (Company c : cList) { c.display(depth + 2); } } @Override protected void romove(Company company) { // TODO Auto-generated method stub cList.remove(company); } } 兩個葉結點類: -------------------------1---------------------------. package com.zyh.designpattern.composite; public class HRDepartment extends Company { public HRDepartment(String name) { super(name); } @Override protected void add(Company company) { } @Override protected void display(int depth) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(""); for (int i = 0; i < depth; i++) { sb.append("-"); } System.out.println(new String(sb) + this.getName()); } @Override protected void romove(Company company) { } } ----------------2------------------- package com.zyh.designpattern.composite; public class FinanceDepartment extends Company { public FinanceDepartment(String name) { super(name); } @Override protected void add(Company company) { } @Override protected void display(int depth) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(""); for (int i = 0; i < depth; i++) { sb.append("-"); } System.out.println(new String(sb) + this.getName()); } @Override protected void romove(Company company) { } } 客戶端: package com.zyh.designpattern.composite; public class Client { public static void main(String[] args) { // TODO Auto-generated method stub Company root = new ConcreteCompany(); root.setName("北京總公司"); root.add(new HRDepartment("總公司人力資源部")); root.add(new FinanceDepartment("總公司財務部")); Company shandongCom = new ConcreteCompany("山東分公司"); shandongCom.add(new HRDepartment("山東分公司人力資源部")); shandongCom.add(new FinanceDepartment("山東分公司賬務部")); Company zaozhuangCom = new ConcreteCompany("棗庄辦事處"); zaozhuangCom.add(new FinanceDepartment("棗庄辦事處財務部")); zaozhuangCom.add(new HRDepartment("棗庄辦事處人力資源部")); Company jinanCom = new ConcreteCompany("濟南辦事處"); jinanCom.add(new FinanceDepartment("濟南辦事處財務部")); jinanCom.add(new HRDepartment("濟南辦事處人力資源部")); shandongCom.add(jinanCom); shandongCom.add(zaozhuangCom); Company huadongCom = new ConcreteCompany("上海華東分公司"); huadongCom.add(new HRDepartment("上海華東分公司人力資源部")); huadongCom.add(new FinanceDepartment("上海華東分公司賬務部")); Company hangzhouCom = new ConcreteCompany("杭州辦事處"); hangzhouCom.add(new FinanceDepartment("杭州辦事處財務部")); hangzhouCom.add(new HRDepartment("杭州辦事處人力資源部")); Company nanjingCom = new ConcreteCompany("南京辦事處"); nanjingCom.add(new FinanceDepartment("南京辦事處財務部")); nanjingCom.add(new HRDepartment("南京辦事處人力資源部")); huadongCom.add(hangzhouCom); huadongCom.add(nanjingCom); root.add(shandongCom); root.add(huadongCom); root.display(0); } }
5. 裝飾者模式
動態的給一個對象添加一些額外的職責
目的: 需要擴展一個類的功能, 或給一個類增加額外的功能, 例如: 比如生日蛋糕, 有一些級別的蛋糕的情況, 比如, 巧克力蛋糕, 草莓蛋糕等, 但是, 要想在蛋糕上單獨加一些東西, 比如加一些花, 等等, 這樣, 就可以將基本的蛋糕采用繼承關系, 而裝飾者有個抽象類, 那些加的花啊什么的, 都是繼承這個裝飾者類, 參考下邊類圖
6. 代理模式
為其他對象提供一種代理以控制對這個對象的訪問
目的: 對對象訪問進行控制, 比如西門慶找潘金蓮,那潘金蓮不好意思答復呀,咋辦,找那個王婆做代理,表現在程序上時是這樣的體現的
代碼如下:
package com.yangguangfu.proxy; /** * * @author 阿福(trygf521@126.com)<br> *定義一種類型的女人,王婆和潘金蓮都屬於這個類型的女人 */ public interface KindWoman { //這種女人能做什么事情呢? public void makeEyesWithMan();//拋媚眼 public void happyWithMan();//和男人那個.... }
一種類型嘛,那肯定是接口,定義個潘金蓮
package com.yangguangfu.proxy; /** * * @author 阿福(trygf521@126.com)<br> *定義一個潘金蓮是什么樣的人 */ public class PanJinLian implements KindWoman{ @Override public void happyWithMan() { System.out.println("潘金蓮和男人在做那個..."); } @Override public void makeEyesWithMan() { System.out.println("潘金蓮拋媚眼..."); } }
再定義個丑陋的王婆
package com.yangguangfu.proxy; /** * * @author 阿福(trygf521@126.com)<br> *王婆這個人老聰明了,她太老了,是個男人都看不上她, *但是她有智慧經驗呀,他作為一類女人的代理! */ public class WangPo implements KindWoman { private KindWoman kindWoman; public WangPo(){ //默認的話是潘金蓮的代理 this.kindWoman = new PanJinLian(); } //她可以是KindWomam的任何一個女人的代理,只要你是這一類型 public WangPo(KindWoman kindWoman){ this.kindWoman = kindWoman; } @Override public void happyWithMan() { //自己老了,干不了了,但可以叫年輕的代替。 this.kindWoman.happyWithMan(); } @Override public void makeEyesWithMan() { //王婆年紀大了,誰看她拋媚眼啊 this.kindWoman.makeEyesWithMan(); } }
兩個女主角都上場了,該男主角了,定義個西門慶
package com.yangguangfu.proxy; /** * * @author 阿福(trygf521@126.com)<br> *水滸傳是這樣寫的:西門慶被潘金蓮用竹竿敲了一下,西門慶看痴迷了,被王婆看到了,就開始撮合兩人好事,王婆作為潘金蓮的代理人收了不少好處費,那我們假設一下: *如果沒有王婆在中間牽線,這兩個不要臉的能成事嗎?難說得很! */ public class XiMenQiang { /** * @param args */ public static void main(String[] args) { WangPo wangPo; //把王婆叫出來 wangPo = new WangPo(); //然后西門慶說,我要和潘金蓮Happy,然后王婆就安排了西門慶丟筷子哪出戲: wangPo.makeEyesWithMan(); //看到沒有表面是王婆在做,其實爽的是潘金蓮 wangPo.happyWithMan(); } }
7. 外觀模式
為子系統中的一組接口提供一個一致的界面
比如: 不知道大家有沒有比較過自己泡茶和去茶館喝茶的區別,如果是自己泡茶需要自行准備茶葉、茶具和開水,如圖1(A)所示,而去茶館喝茶,最簡單的方式就是跟茶館服務員說想要一杯什么樣的茶,是鐵觀音、碧螺春還是西湖龍井?正因為茶館有服務員,顧客無須直接和茶葉、茶具、開水等交互,整個泡茶過程由服務員來完成,顧客只需與服務員交互即可,整個過程非常簡單省事,如圖1(B)所示
在軟件開發中,有時候為了完成一項較為復雜的功能,一個客戶類需要和多個業務類交互,而這些需要交互的業務類經常會作為一個整體出現,由於涉及到的類比較多,導致使用時代碼較為復雜,此時,特別需要一個類似服務員一樣的角色,由它來負責和多個業務類進行交互,而客戶類只需與該類交互。外觀模式通過引入一個新的外觀類(Facade)來實現該功能,外觀類充當了軟件系統中的“服務員”,它為多個業務類的調用提供了一個統一的入口,簡化了類與類之間的交互。在外觀模式中,那些需要交互的業務類被稱為子系統(Subsystem)。如果沒有外觀類,那么每個客戶類需要和多個子系統之間進行復雜的交互,系統的耦合度將很大,如圖2(A)所示;而引入外觀類之后,客戶類只需要直接與外觀類交互,客戶類與子系統之間原有的復雜引用關系由外觀類來實現,從而降低了系統的耦合度,如圖2(B)所示。
8. 橋梁模式
橋梁模式將抽象部分與它的實現部分分離
目的: 比如我們有一個畫圖程序 有2個圖形(Circle Rectangle )和2種畫圖方法(Drawing1 Drawing2)圖形可能會使用Drawing1來畫圖 也可能使用Drawing2來畫圖在這個畫圖程序中有兩個可變因素 一個是圖形的種類 有可能會增加新的圖形 另一個是畫圖方法 可能會有Drawing3出現.
9. 中介者模式
中介者模式用一個中介對象封裝一系列的對象交互
目的: 比如 在生活中,當電腦缺少了一塊主板,那會怎么樣?如果有人這樣問我的話,我就會馬上跳出來說“這電腦肯定報廢了”,當然這不是重點。假如少了主板電腦還可以用的話,想想,里面的CPU、顯卡、聲卡、光驅、硬盤等等,不是就要我們自己用線把它們連起來。想想就覺得頭疼,那么現在你覺得主板在電腦里扮演着什么角色呢?
例2:
Mediator:中介者接口。在里面定義了各個同事之間相互交互所需要的方法,可以是公共的方法,如Change方法,也可以是小范圍的交互方法
ConcreteMediator:具體的中介者實現對象。它需要了解並為維護每個同事對象,並負責具體的協調各個同事對象的交互關系。
Colleague:同事類的定義,通常實現成為抽象類,主要負責約束同事對象的類型,並實現一些具體同事類之間的公共功能,比如,每個具體同事類都應該知道中介者對象,也就是每個同事對象都會持有中介者對象的引用,這個功能可定義在這個類中。
ConcreteColleague:具體的同事類,實現自己的業務,需要與其他同事對象交互時,就通知中介對象,中介對象會負責后續的交互。
10. 策略模式
策略模式定義一系列的算法,把它們一個個封裝起來,並且使它們可以相互替換
比如:
劉備要到江東娶老婆了,走之前諸葛亮給趙雲(伴郎)三個錦囊妙計,說是按天機拆開能解決棘手問題,嘿,還別說,真解決了大問題,搞到最后是周瑜陪了夫人又折兵,那咱們先看看這個場景是什么樣子的。
先說說這個場景中的要素:三個妙計,一個錦囊,一個趙雲,妙計是亮哥給的,妙計放在錦囊里,俗稱就是錦囊妙計嘛,那趙雲就是一個干活的人,從錦囊取出妙計,執行,然后獲勝。用java程序怎么表現這些呢?
那我們先來看看圖
三個妙計是同一類型的東西,那咱就寫個接口:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 首先定義一個策略接口,這是諸葛亮老人家給趙雲的三個錦囊妙計的接口。 */ public interface IStrategy { //每個錦囊妙計都是一個可執行的算法。 public void operate(); }
然后再寫三個實現類,有三個妙計嘛:
妙計一:初到吳國:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 找喬國老幫忙,使孫權不能殺劉備。 */ public class BackDoor implements IStrategy { @Override public void operate() { System.out.println("找喬國老幫忙,讓吳國太給孫權施加壓力,使孫權不能殺劉備..."); } }
妙計二:求吳國太開個綠燈,放行:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 求吳國太開個綠燈。 */ public class GivenGreenLight implements IStrategy { @Override public void operate() { System.out.println("求吳國太開個綠燈,放行!"); } }
妙計三:孫夫人斷后,擋住追兵:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * 孫夫人斷后,擋住追兵。 */ public class BlackEnemy implements IStrategy { @Override public void operate() { System.out.println("孫夫人斷后,擋住追兵..."); } } 好了,大家看看,三個妙計是有了,那需要有個地方放妙計啊,放錦囊里:
package com.yangguangfu.strategy; /** * * @author trygf521@126.com:阿福 * */ public class Context { private IStrategy strategy; //構造函數,要你使用哪個妙計 public Context(IStrategy strategy){ this.strategy = strategy; } public void operate(){ this.strategy.operate(); } }
然后就是趙雲雄赳赳的揣着三個錦囊,拉着已步入老年行列,還想着娶純情少女的,色咪咪的劉備老爺子去入贅了,嗨,還別說,亮哥的三個妙計還真不錯,瞧瞧:
package com.yangguangfu.strategy; public class ZhaoYun { /** * 趙雲出場了,他根據諸葛亮給他的交代,依次拆開妙計 */ public static void main(String[] args) { Context context; //剛到吳國的時候拆開第一個 System.out.println("----------剛剛到吳國的時候拆開第一個---------------"); context = new Context(new BackDoor()); context.operate();//拆開執行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); //當劉備樂不思蜀時,拆開第二個 System.out.println("----------劉備樂不思蜀,拆第二個了---------------"); context = new Context(new GivenGreenLight()); context.operate();//拆開執行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); //孫權的小追兵了,咋辦?拆開第三個錦囊 System.out.println("----------孫權的小追兵了,咋辦?拆開第三個錦囊---------------"); context = new Context(new BlackEnemy()); context.operate();//拆開執行 System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n"); } }
11. 模板模式
定義一個操作中的算法骨架, 而將一些步驟延遲到子類中
個人感覺是定義一套流程”即算法骨架”, 置於骨架的內容, 要到實現時, 會有不同
比如: 我們使用沖泡咖啡和沖泡茶的例子
加工流程:
咖啡沖泡法:1.把水煮沸、2.用沸水沖泡咖啡、3.把咖啡倒進杯子、4.加糖和牛奶
茶沖泡法: 1.把水煮沸、2.用沸水沖泡茶葉、3.把 茶 倒進杯子、4.加蜂蜜
實踐步驟:
1>創建一個模板(抽象)類:Beverage(飲料) 這里包含”骨架”
package com.kaishengit.beverage; public abstract class Beverage { /** * 沖泡咖啡或茶...流程 */ public final void create(){ boilWater();//把水煮沸 brew();//用沸水沖泡... pourInCup();//把...倒進杯子 addCoundiments();//加... } public abstract void addCoundiments(); public abstract void brew(); public void boilWater() { System.out.println("煮開水"); } public void pourInCup() { System.out.println("倒進杯子"); } }
2>創建一個咖啡類(Coffee)和茶(Tea)類,都繼承Beverage抽象類
1.咖啡(Coffee)
package com.kaishengit.beverage; public class Coffee extends Beverage{ @Override public void addCoundiments() { System.out.println("添加糖和牛奶"); } @Override public void brew() { System.out.println("用水沖咖啡"); } }
2. 茶(Tea)
package com.kaishengit.beverage; public class Tea extends Beverage{ @Override public void addCoundiments() { System.out.println("添加蜂蜜"); } @Override public void brew() { System.out.println("用水沖茶"); } }
12. 觀察者模式
定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一主題對象
模式中的角色
抽象主題(Subject):它把所有觀察者對象的引用保存到一個聚集里,每個主題都可以有任何數量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象。
具體主題(ConcreteSubject):將有關狀態存入具體觀察者對象;在具體主題內部狀態改變時,給所有登記過的觀察者發出通知。
抽象觀察者(Observer):為所有的具體觀察者定義一個接口,在得到主題通知時更新自己。
具體觀察者(ConcreteObserver):實現抽象觀察者角色所要求的更新接口,以便使本身的狀態與主題狀態協調
想想自己blog的氣象站的例子(headfirst 設計模式中的例子)
13. 迭代器模式
迭代器模式提供一種方法順序訪問一個聚合對象中各個元素
迭代器角色(Iterator):迭代器角色負責定義訪問和遍歷元素的接口
具體迭代器角色(Concrete Iterator):具體迭代器角色要實現迭代器接口,並要記錄遍歷中的當前位置。
Aggregate (聚合): 聚合定義創建相應迭代器對象的接口
ConcreteAggregate (具體聚合): 具體聚合實現創建相應迭代器的接口,該操作返回ConcreteIterator的一個適當的實例
比如: 早期電視機, 按電視上按鈕換台那種, 當我們換頻道時, 重要的不是幾頻道, 而是節目內容.
在面向對象的軟件設計中, 我們經常會遇到一類集合對象, 這類集合對象的內部結構可能有着各種各樣的實現, 但是歸結起來, 無非有兩點是我們關心的: 一是集合內部的數據存儲結構, 二是遍歷這個集合內部的數據. Iterator 模式就是分離了集合對象的遍歷行為.
首先有一個抽象的聚集, 所謂聚集就是數據的集合, 可以循環去訪問它, 它只有一個方法 GetIterator()讓子類去實現, 用來獲得一個迭代器對象.
抽象迭代器: Iterator, 它用來訪問聚集的類, 封裝了一些方法, 通常會有 MoveNext(), CurrentItem(), First(), Next()
具體聚集 ConcreteList: 它實現了抽象聚集中的唯一方法, 同時再里面保存了一組數據
具體迭代器 ConcreteIterator: 具體迭代器, 它實現了迭代器中的4個方法, 在它的構造函數中需要接受一個具體聚集類型的參數.
14. 責任鏈模式
責任鏈模式使多個對象都有機會處理請求
抽象處理者 Handler: 定義出一個處理請求的接口,如果需要,接口可以定義出一個方法,以設定和返回對下家的引用。這個角色通常由一個抽象類或接口實現。
具體處理者(ConcreteHandler)角色:具體處理者接到請求后,可以選擇將請求處理掉,或者將請求傳給下家。由於具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家。
比如: 請假,審批的例子, 在公司里,如果你的請假時間小於0.5天,那么只需要向項目經理打聲招呼就OK了, 如果超過了0.5天,但是還小於2天,那么就要去找人事部處理,當然,這就要扣工資了, 如果超過了2天,你就需要去找總經理了,工資當然也玩完了。那么,對於我們來說,這個流程就是這樣的。
也就是這樣一個過程,你需要和你的直接上級——項目經理去打交道,最終可能是項目經理給你回郵件,可能是人事部給你回郵件,也可能是總經理給你回郵件。內部的過程其實應該是個黑盒子,你並不知道內部的消息是如何處理的。你需要找到的,只是你想要第一個交付的對象而已.
下邊是一個審批例子的具體代碼.
抽象處理者角色
public abstract class Handler { /** * 持有下一個處理請求的對象 */ protected Handler successor = null; /** * 取值方法 */ public Handler getSuccessor() { return successor; } /** * 設置下一個處理請求的對象 */ public void setSuccessor(Handler successor) { this.successor = successor; } /** * 處理聚餐費用的申請 * @param user 申請人 * @param fee 申請的錢數 * @return 成功或失敗的具體通知 */ public abstract String handleFeeRequest(String user , double fee);
具體處理者角色
項目經理
public class ProjectManager extends Handler { @Override public String handleFeeRequest(String user, double fee) { String str = ""; //項目經理權限比較小,只能在500以內 if(fee < 500) { //為了測試,簡單點,只同意張三的請求 if("張三".equals(user)) { str = "成功:項目經理同意【" + user + "】的聚餐費用,金額為" + fee + "元"; }else { //其他人一律不同意 str = "失敗:項目經理不同意【" + user + "】的聚餐費用,金額為" + fee + "元"; } }else { //超過500,繼續傳遞給級別更高的人處理 if(getSuccessor() != null) { return getSuccessor().handleFeeRequest(user, fee); } } return str; } }
部門經理
public class DeptManager extends Handler { @Override public String handleFeeRequest(String user, double fee) { String str = ""; //部門經理的權限只能在1000以內 if(fee < 1000) { //為了測試,簡單點,只同意張三的請求 if("張三".equals(user)) { str = "成功:部門經理同意【" + user + "】的聚餐費用,金額為" + fee + "元"; }else { //其他人一律不同意 str = "失敗:部門經理不同意【" + user + "】的聚餐費用,金額為" + fee + "元"; } }else { //超過1000,繼續傳遞給級別更高的人處理 if(getSuccessor() != null) { return getSuccessor().handleFeeRequest(user, fee); } } return str; } }
部長
public class GeneralManager extends Handler { @Override public String handleFeeRequest(String user, double fee) { String str = ""; //總經理的權限很大,只要請求到了這里,他都可以處理 if(fee >= 1000) { //為了測試,簡單點,只同意張三的請求 if("張三".equals(user)) { str = "成功:總經理同意【" + user + "】的聚餐費用,金額為" + fee + "元"; }else { //其他人一律不同意 str = "失敗:總經理不同意【" + user + "】的聚餐費用,金額為" + fee + "元"; } }else { //如果還有后繼的處理對象,繼續傳遞 if(getSuccessor() != null) { return getSuccessor().handleFeeRequest(user, fee); } } return str; } }
客戶端類 (測試)
public class Client { public static void main(String[] args) { //先要組裝責任鏈 Handler h1 = new GeneralManager(); Handler h2 = new DeptManager(); Handler h3 = new ProjectManager(); h3.setSuccessor(h2); h2.setSuccessor(h1); //開始測試 String test1 = h3.handleFeeRequest("張三", 300); System.out.println("test1 = " + test1); String test2 = h3.handleFeeRequest("李四", 300); System.out.println("test2 = " + test2); System.out.println("---------------------------------------"); String test3 = h3.handleFeeRequest("張三", 700); System.out.println("test3 = " + test3); String test4 = h3.handleFeeRequest("李四", 700); System.out.println("test4 = " + test4); System.out.println("---------------------------------------"); String test5 = h3.handleFeeRequest("張三", 1500); System.out.println("test5 = " + test5); String test6 = h3.handleFeeRequest("李四", 1500); System.out.println("test6 = " + test6); } }
輸出結果:
15. 命令模式
將一個請求封裝成為一個對象, 使可以用不同的請求對客戶進行參數化
命令角色(Command):聲明執行操作的接口。有java接口或者抽象類來實現。
具體命令角色(Concrete Command):將一個接收者對象綁定於一個動作;調用接收者相應的操作,以實現命令角色聲明的執行操作的接口
客戶角色(Client):創建一個具體命令對象(並可以設定它的接收者
請求者角色(Invoker):調用命令對象執行這個請求
接收者角色(Receiver):知道如何實施與執行一個請求相關的操作。任何類都可能作為一個接收者
比如: 電視機遙控器
電視機是請求的接收者Receiver,遙控器是請求的發送者Invoker, 遙控器上有一些按鈕,不同的按鈕對應電視機的不同操作Command. 抽象命令角色由一個命令接口來扮演, 有三個具體的命令類實現了抽象命令接口,這三個具體命令類分別代表三種操作:打開電視機、關閉電視機和切換頻道
代碼如下:
public interface Command { public void execute(); } public class ConcreteCommand implements Command { private Receiver receiver = null; private String state; public ConcreteCommand(Receiver receiver){ this.receiver = receiver; } public void execute() { receiver.action(); } } public class Receiver { public void action(){ //真正執行命令操作的功能代碼 } } public class Invoker { private Command command = null; public void setCommand(Command command) { this.command = command; } public void runCommand() { command.execute(); } } public class Client { public void assemble(){ //創建接收者 Receiver receiver = new Receiver(); //創建命令對象,設定它的接收者 Command command = new ConcreteCommand(receiver); //創建Invoker,把命令對象設置進去 Invoker invoker = new Invoker(); invoker.setCommand(command); } }
模擬電視機換台的代碼:
下面給個例子,是模擬對電視機的操作有開機、關機、換台命令。代碼如下 //命令接收者 public class Tv { public int currentChannel = 0; public void turnOn() { System.out.println("The televisino is on."); } public void turnOff() { System.out.println("The television is off."); } public void changeChannel(int channel) { this.currentChannel = channel; System.out.println("Now TV channel is " + channel); } } //執行命令的接口 public interface Command { void execute(); } //開機命令 public class CommandOn implements Command { private Tv myTv; public CommandOn(Tv tv) { myTv = tv; } public void execute() { myTv.turnOn(); } } //關機命令 public class CommandOff implements Command { private Tv myTv; public CommandOff(Tv tv) { myTv = tv; } public void execute() { myTv.turnOff(); } } //頻道切換命令 public class CommandChange implements Command { private Tv myTv; private int channel; public CommandChange(Tv tv, int channel) { myTv = tv; this.channel = channel; } public void execute() { myTv.changeChannel(channel); } } //可以看作是遙控器吧 public class Control { private Command onCommand, offCommand, changeChannel; public Control(Command on, Command off, Command channel) { onCommand = on; offCommand = off; changeChannel = channel; } public void turnOn() { onCommand.execute(); } public void turnOff() { offCommand.execute(); } public void changeChannel() { changeChannel.execute(); } } //測試類 public class Client { public static void main(String[] args) { // 命令接收者 Tv myTv = new Tv(); // 開機命令 CommandOn on = new CommandOn(myTv); // 關機命令 CommandOff off = new CommandOff(myTv); // 頻道切換命令 CommandChange channel = new CommandChange(myTv, 2); // 命令控制對象 Control control = new Control(on, off, channel); // 開機 control.turnOn(); // 切換頻道 control.changeChannel(); // 關機 control.turnOff(); } } 執行結果為: The televisino is on. Now TV channel is 2 The television is off.
16. 狀態模式
狀態模式容許一個對象在其內部狀態改變時改變它的行為
上下文環境(Context):它定義了客戶程序需要的接口並維護一個具體狀態角色的實例,將與狀態相關的操作委托給當前的Concrete State對象來處理.
抽象狀態(State):定義一個接口以封裝使用上下文環境的的一個特定狀態相關的行為
具體狀態(Concrete State):實現抽象狀態定義的接口
舉例:
電燈有兩個狀態,開(亮)與關(不亮),下面就用狀態模式來實現對電燈的控制
/// <summary> /// 電燈類,對應模式中的Context類 /// </summary> public class Light { private LightState state; public Light(LightState state) { this.state = state; } /// <summary> /// 按下電燈開關 /// </summary> public void PressSwich() { state.PressSwich(this); } public LightState State { get { return state; } set { state = value; } } } /// <summary> /// 抽象的電燈狀態類,相當於State類 /// </summary> public abstract class LightState { public abstract void PressSwich(Light light); } /// <summary> /// 具體狀態類, 開 /// </summary> public class On : LightState { /// <summary> /// 在開狀態下,按下開關則切換到關的狀態。 /// </summary> /// <param name="light"></param> public override void PressSwich(Light light) { Console.WriteLine("Turn off the light."); light.State = new Off(); } } /// <summary> /// 具體狀態類,關 /// </summary> public class Off: LightState { /// <summary> /// 在關狀態下,按下開關則打開電燈。 /// </summary> /// <param name="light"></param> public override void PressSwich(Light light) { Console.WriteLine("Turn on the light."); light.State = new On(); } }
客戶端代碼
class Program { static void Main(string[] args) { // 初始化電燈,原始狀態為關 Light light = new Light(new Off()); // 第一次按下開關,打開電燈 light.PressSwich(); // 第二次按下開關,關閉電燈 light.PressSwich(); Console.Read(); } }