行為型模式用于描述程序在運行時復雜的流程控制,即描述多個類或對象之間怎樣相互協作共同完成單個對象都無法單獨完成的任務,它涉及算法與對象間職責的分配。
行為型模式分為類行為模式和對象行為模式,前者采用繼承機制來在類間分派行為,后者采用組合或聚合在對象間分配行為。由于組合關系或聚合關系比繼承關系耦合度低,滿足“合成復用原則”,所以對象行為模式比類行為模式具有更大的靈活性。
行為型模式分為:
- 模板方法模式
- 策略模式
- 命令模式
- 職責鏈模式
- 狀態模式
- 觀察者模式
- 中介者模式
- 迭代器模式
- 訪問者模式
- 備忘錄模式
- 解釋器模式
以上 11 種行為型模式,除了模板方法模式和解釋器模式是類行為型模式,其他的全部屬于對象行為型模式。
6.1 模板方法模式
6.1.1 概述
在面向對象程序設計過程中,程序員常常會遇到這種情況:設計一個系統時知道了算法所需的關鍵步驟,而且確定了這些步驟的執行順序,但某些步驟的具體實現還未知,或者說某些步驟的實現與具體的環境相關。
例如,去銀行辦理業務一般要經過以下4個流程:取號、排隊、辦理具體業務、對銀行工作人員進行評分等,其中取號、排隊和對銀行工作人員進行評分的業務對每個客戶是一樣的,可以在父類中實現,但是辦理具體業務卻因人而異,它可能是存款、取款或者轉賬等,可以延遲到子類中實現。
定義:
定義一個操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變該算法結構的情況下重定義該算法的某些特定步驟。
6.1.2 結構
模板方法(Template Method)模式包含以下主要角色:
-
抽象類(Abstract Class):負責給出一個算法的輪廓和骨架。它由一個模板方法和若干個基本方法構成。
-
模板方法:定義了算法的骨架,按某種順序調用其包含的基本方法。
-
基本方法:是實現算法各個步驟的方法,是模板方法的組成部分。基本方法又可以分為三種:
-
抽象方法(Abstract Method) :一個抽象方法由抽象類聲明、由其具體子類實現。
-
具體方法(Concrete Method) :一個具體方法由一個抽象類或具體類聲明并實現,其子類可以進行覆蓋也可以直接繼承。
-
鉤子方法(Hook Method) :在抽象類中已經實現,包括用于判斷的邏輯方法和需要子類重寫的空方法兩種。
一般鉤子方法是用于判斷的邏輯方法,這類方法名一般為isXxx,返回值類型為boolean類型。
-
-
-
具體子類(Concrete Class):實現抽象類中所定義的抽象方法和鉤子方法,它們是一個頂級邏輯的組成步驟。
6.1.3 案例實現
【例】炒菜
炒菜的步驟是固定的,分為倒油、熱油、倒蔬菜、倒調料品、翻炒等步驟。現通過模板方法模式來用代碼模擬。類圖如下:
代碼如下:
abstract class AbstractClass {//模板方法,為防止惡意操作,一般模板方法都加上 final 關鍵詞。public final void cookProcess() {//第一步:倒油this.pourOil();//第二步:熱油this.heatOil();//第三步:倒蔬菜this.pourVegetable();//第四步:倒調味料this.pourSauce();//第五步:翻炒this.fry();}public void pourOil() {System.out.println("倒油");}//第二步:熱油是一樣的,所以直接實現public void heatOil() {System.out.println("熱油");}//第三步:倒蔬菜是不一樣的(一個下包菜,一個是下菜心)public abstract void pourVegetable();//第四步:倒調味料是不一樣public abstract void pourSauce();//第五步:翻炒是一樣的,所以直接實現public void fry(){System.out.println("炒啊炒啊炒到熟啊");}
}
class ConcreteClass_BaoCai extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下鍋的蔬菜是包菜");}@Overridepublic void pourSauce() {System.out.println("下鍋的醬料是辣椒");}
}
class ConcreteClass_CaiXin extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下鍋的蔬菜是菜心");}@Overridepublic void pourSauce() {System.out.println("下鍋的醬料是蒜蓉");}
}
public class Client {public static void main(String[] args) {//炒手撕包菜ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();baoCai.cookProcess();//炒蒜蓉菜心ConcreteClass_CaiXin caiXin = new ConcreteClass_CaiXin();caiXin.cookProcess();}
}
倒油
熱油
下鍋的蔬菜是包菜
下鍋的醬料是辣椒
炒啊炒啊炒到熟啊
倒油
熱油
下鍋的蔬菜是菜心
下鍋的醬料是蒜蓉
炒啊炒啊炒到熟啊
6.1.3 優缺點
優點:
-
提高代碼復用性
將相同部分的代碼放在抽象的父類中,而將不同的代碼放入不同的子類中。
-
實現了反向控制
通過一個父類調用其子類的操作,通過對子類的具體實現擴展不同的行為,實現了反向控制 ,并符合“開閉原則”。
缺點:
- 對每個不同的實現都需要定義一個子類,這會導致類的個數增加,系統更加龐大,設計也更加抽象。
- 父類中的抽象方法由子類實現,子類執行的結果會影響父類的結果,這導致一種反向的控制結構,它提高了代碼閱讀的難度。
6.1.4 適用場景
- 算法的整體步驟很固定,但其中個別部分易變時,這時候可以使用模板方法模式,將容易變的部分抽象出來,供子類實現。
- 需要通過子類來決定父類算法中某個步驟是否執行,實現子類對父類的反向控制。
6.2 策略模式
6.2.1 概述
先看下面的圖片,我們去旅游選擇出行模式有很多種,可以騎自行車、可以坐汽車、可以坐火車、可以坐飛機。
作為一個程序猿,開發需要選擇一款開發工具,當然可以進行代碼開發的工具有很多,可以選擇Idea進行開發,也可以使用eclipse進行開發,也可以使用其他的一些開發工具。
定義:
該模式定義了一系列算法,并將每個算法封裝起來,使它們可以相互替換,且算法的變化不會影響使用算法的客戶。策略模式屬于對象行為模式,它通過對算法進行封裝,把使用算法的責任和算法的實現分割開來,并委派給不同的對象對這些算法進行管理。
6.2.2 結構
策略模式的主要角色如下:
- 抽象策略(Strategy)類:這是一個抽象角色,通常由一個接口或抽象類實現。此角色給出所有的具體策略類所需的接口。
- 具體策略(Concrete Strategy)類:實現了抽象策略定義的接口,提供具體的算法實現或行為。
- 環境(Context)類:持有一個策略類的引用,最終給客戶端調用。
6.2.3 案例實現
【例】促銷活動
一家百貨公司在定年度的促銷活動。針對不同的節日(春節、中秋節、圣誕節)推出不同的促銷活動,由促銷員將促銷活動展示給客戶。類圖如下:
//抽象策略類
interface Strategy {void show();
}
//具體策略類,為春節準備的促銷活動A
class StrategyA implements Strategy {public void show() {System.out.println("買一送一");}
}
//為中秋準備的促銷活動B
class StrategyB implements Strategy {public void show() {System.out.println("滿200元減50元");}
}
//為圣誕準備的促銷活動C
class StrategyC implements Strategy {public void show() {System.out.println("滿1000元加一元換購任意200元以下商品");}
}
//環境類
class SalesMan {//持有抽象策略角色的引用private Strategy strategy;public SalesMan(Strategy strategy) {this.strategy = strategy;}//向客戶展示促銷活動public void salesManShow() {strategy.show();}
}
class Test {public static void main(String[] args) {Strategy strategy = new StrategyB();SalesMan salesMan = new SalesMan(strategy);salesMan.salesManShow();}
}
6.2.4 優缺點
1,優點:
-
策略類之間可以自由切換
由于策略類都實現同一個接口,所以使它們之間可以自由切換