1. 委派模式
1.1 委派模式的簡介
- 委派模式不屬于
GOF23種設計模式中, - 委派模式(
Delegate Pattern)的基本作用就是負責任務的呼叫和分配任務,跟代理模式很像,可以看做是一種特殊情況下的靜態代理 的全權代理,但是代理模式注重程序,而委派模式注重結果,
1.2 委派模式的使用場景
-
委派模式在
Spring中應用非常多,大家常用的DispatcherServlet其實就是用到了委派模式, -
現實生活中也常有委 派的場景發生,例如:老板(Boss)給專案經理(Leader)下達任務,專案經理會根據 實際情況給每個員工派發作業任務,待員工把作業任務完成之后,再由專案經理匯報工 作進度和結果給老板,
1.3 場景實作
-
上述作業中的場景是大家熟悉的,當
Boss給Leader下發任務后,Leader會根據實際情況來分配給回應的組員,我們將這一實際場景進行抽象化處理,用代碼來進行實作 -
首先我們要明確其中的關系,客戶請求(Boss)、委派者(Leader)、被委派者(Target) 在這個構建中 委派者與被委派者都服務與客戶請求,只是真實的操作時讓被委派者執行的,有點像靜態代理
-
總體模型視圖如下:

- 撰寫
Leader與Target的共有父介面
public interface IEmployee {
void doWork(String commd);
}
- 撰寫相應的實作類
撰寫普通員工類:
public class EmployeeA implements IEmployee {
@Override
public void doWork(String commd) {
System.out.println("EmployeeA 正在處理 "+commd +"任務");
}
}
public class EmployeeB implements IEmployee {
@Override
public void doWork(String commd) {
System.out.println("EmployeeB 正在處理 "+commd +"任務");
}
}
撰寫 Leader 實作:
public class Leader implements IEmployee {
private static Map<String,IEmployee> handlerMapping = new HashMap<>();
public Leader(){
//初始化規則
handlerMapping.put("Login",new EmployeeA());
handlerMapping.put("Pay",new EmployeeB());
}
@Override
public void doWork(String commd) {
handlerMapping.get(commd).doWork(commd);
}
}
在初始化 Leader 時我們首先將對應的規則記錄,也就是委派的規則,那些任務需要派給
A, 那么任務需要派給B,后期的其他需求也是在這里進行擴展
撰寫 Boss 類:
/**
* @author: anonystar
* @time: 2020/5/27 16:48
*/
public class Boss {
private Leader leader;
public Boss(Leader leader){
this.leader = leader;
}
public void command(String cmd) {
//委派分發
leader.doWork(cmd);
}
}
測驗代碼:
/**
* @author: anonystar
* @time: 2020/5/28 9:40
*/
public class SimpleDelegateTest {
public static void main(String[] args) {
//客戶請求(Boss)、委派者(Leader)、被被委派者(Target)
// 委派者要持有被委派者的參考
// 代理模式注重的是程序, 委派模式注重的是結果
// 策略模式注重是可擴展(外部擴展),委派模式注重內部的靈活和復用
// 委派的核心:就是分發、調度、派遣
//
Boss boss = new Boss(new Leader());
boss.command("Pay");
}
}
1.4 小結
-
我們通過上面代碼可以發現委派模式就是靜態代理和策略模式一種特殊的組合
-
代理模式注重的是程序, 委派模式更注重的是結果
-
委派者要持有被委派者的參考
-
委派的核心:就是分發、調度、派遣
2. 策略模式
2.1 策略模式簡介
-
策略模式是一種行為設計模式, 它能讓你定義一系列演算法, 并將每種演算法分別放入獨立的類中, 以使演算法的物件能夠相互替換,
-
此模式讓演算法的變化不會影響到使用演算法的用戶
2.2 場景適用
-
1、假如系統中有很多類,而他們的區別僅僅在于他們的行為不同,
-
2、一個系統需要動態地在幾種演算法中選擇一種,
2.3 場景模擬
2.3.1 場景問題提出
前提:
-
假設你為旅游者們設計了一款導游程式, 該程式的核心功能是提供美觀的地圖, 以幫助用戶在任何城市中快速定位,
-
用戶期待的程式新功能是自動路線規劃: 他們希望輸入地址后就能在地圖上看到前往目的地的最快路線,
-
程式的首個版本只能規劃公路路線,這滿足了駕車旅行的人們的需求,但是也很明顯的會忽略其他選擇,所以你需要在一次次的迭代中增加新的規劃線路方案,如增加步行線路、公共交通線路等等,
-
你以為這樣就夠了?這只是個開始,沒多久時間你又要為騎行者規劃路線, 又過了一段時間, 你又要為游覽城市中的所有景點規劃路線,此時相信面對不斷臃腫的代碼已經苦不堪言了,每次都的改動大量的代碼
實際問題:
-
每次線路的增加都讓整個開發團隊非常頭痛,因為每次增加新的線路規劃后整個代碼中的主體類都會增加一倍,慢慢的整個團都都無法繼續維護這大量凌亂的代碼
-
當在使用程序中暴露出缺陷和某些功能的微調時,那么對當前的修改都會影響到整個線路規劃,同時增加了程式運行中的其他風險
-
越到后期團隊合作將變得越低效, 尤其在后期招募了新的團隊成員,他們需要大量的時間來熟悉和適應這些內容,同時在各種版本合并中掙扎,在實作新功能的程序中, 你的團隊需要修改同一個巨大的類, 這樣他們所撰寫的代碼相互之間就可能會出現沖突,
2.3.2 解決方案
- 策略模式建議找出負責用許多不同方式完成特定任務的類, 然后將其中的演算法抽取到一組被稱為策略的獨立類中,
名為背景關系的原始類必須包含一個成員變數來存盤對于每種策略的參考, 背景關系并不執行任務, 而是將作業委派給已連接的策略物件,
背景關系不負責選擇符合任務需要的演算法——客戶端會將所需策略傳遞給背景關系, 實際上, 背景關系并不十分了解策略, 它會通過同樣的通用介面與所有策略進行互動, 而該介面只需暴露一個方法來觸發所選策略中封裝的演算法即可,
因此, 背景關系可獨立于具體策略, 這樣你就可在不修改背景關系代碼或其他策略的情況下添加新演算法或修改已有演算法了,
2.4 代碼實作
- 構建路線頂級介面
/**
* 路線介面
* @author: anonystar
* @url: i-code.online
* @time: 2020/6/8 16:51
*/
public interface Route {
String ROUTE_WALK = "walk";
String ROUTE_CAR = "car";
String ROUTE_CYCLING = "cycling";
public void doRoute();
}
- 實作具體線路方式 如步行線路、駕車線路、騎行線路等,均實作
Route介面
/**
* 駕車線路
* @author: anonystar
* @url: i-code.online
* @time: 2020/6/8 16:58
*/
public class CarRoute implements Route {
@Override
public void doRoute() {
System.out.println("======== 駕車線路 start =========");
}
}
/**
* 騎行線路
* @author: anonystar
* @url: i-code.online
* @time: 2020/6/8 17:01
*/
public class CyclingRoute implements Route {
@Override
public void doRoute() {
System.out.println("======== 騎行線路 start =========");
}
}
/**
* 步行線路
* @author: anonystar
* @url: i-code.online
* @time: 2020/6/8 17:02
*/
public class WalkRoute implements Route {
@Override
public void doRoute() {
System.out.println("======== 步行線路 start =========");
}
}
- 構建路線的背景關系,作為對外使用的唯一入口,呼叫所有的策略均從這里使用
package org.strategy.travel;
/**
* 構建路線 背景關系
* @author: anonystar
* @url: i-code.online
* @time: 2020/6/9 14:45
*/
public class RouteContext {
// 背景關系會維護指向某個策略物件的參考,背景關系不知曉策略的具體類,
// 背景關系必須通過策略介面來與所有策略進行互動,
private Route route;
// 背景關系通常會通過建構式來接收策略物件,
// 同時還提供設定器以便在運行時切換策略,
public RouteContext(Route route){
this.route = route;
}
public void setRoute(Route route) {
this.route = route;
}
// 背景關系會將一些作業委派給策略物件,而不是自行實作不同版本的演算法,
public void execute(){
route.doRoute();
}
}
- 測驗代碼
public void travle3(){
String cmd = "walk";
RouteContext route = null;
if (cmd.equals(Route.ROUTE_WALK)){
route = new RouteContext(new WalkRoute());
}else if (cmd.equals(Route.ROUTE_CAR)){
route = new RouteContext( new CarRoute());
}
route.execute();
}
上面代碼我們會發現如果有很多策略時,那么會造成大量的if陳述句,這里我們可以使用工廠模式來進行簡化,可以看我們之前的文章在i-code.online
- 我們構建一個工廠來簡化創建
package org.strategy.travel;
import java.util.HashMap;
import java.util.Map;
/**
* 獲取背景關系工廠
* @author: anonystar
* @url: i-code.online
* @time: 2020/6/8 17:22
*/
public class RouteContextFactory {
private static Map<String,Route> routeMap = new HashMap<>();
private RouteContextFactory(){
}
static {
routeMap.put(Route.ROUTE_CAR,new CarRoute());
routeMap.put(Route.ROUTE_WALK,new WalkRoute());
routeMap.put(Route.ROUTE_CYCLING,new CyclingRoute());
}
public static RouteContext getRoute(String cmd){
Route route = routeMap.get(cmd);
if ( null == route){
route = routeMap.get(Route.ROUTE_CAR);
}
return new RouteContext(route);
}
}
- 測驗代碼
/**
* 通過工廠方法來簡化
*/
public static void travle4(){
String cmd = "car";
RouteContext route = RouteContextFactory.getRoute(cmd);
route.execute();
}
2.5 使用場景
- 當你想使用物件中各種不同的演算法變體, 并希望能在運行時切換演算法時, 可使用策略模式,
策略模式讓你能夠將物件關聯至可以不同方式執行特定子任務的不同子物件, 從而以間接方式在運行時更改物件行為,
- 當你有許多僅在執行某些行為時略有不同的相似類時, 可使用策略模式,
策略模式讓你能將不同行為抽取到一個獨立類層次結構中, 并將原始類組合成同一個, 從而減少重復代碼,
- 如果演算法在背景關系的邏輯中不是特別重要, 使用該模式能將類的業務邏輯與其演算法實作細節隔離開來,
策略模式讓你能將各種演算法的代碼、 內部資料和依賴關系與其他代碼隔離開來, 不同客戶端可通過一個簡單介面執行演算法, 并能在運行時進行切換,
- 當類中使用了復雜條件運算子以在同一演算法的不同變體中切換時, 可使用該模式,
策略模式將所有繼承自同樣介面的演算法抽取到獨立類中, 因此不再需要條件陳述句, 原始物件并不實作所有演算法的變體, 而是將執行作業委派給其中的一個獨立演算法物件,
2.6 策略模式的優缺點
2.6.1 優點:
- 1、策略模式符合開閉原則,
- 2、避免使用多重條件轉移陳述句,如 if...else... 陳述句、switch 陳述句
- 3、使用策略模式可以提高演算法的保密性和安全性,
2.6.2 缺點:
- 1、客戶端必須知道所有的策略,并且自行決定使用哪一個策略類,
- 2、代碼中會產生非常多策略類,增加維護難度
本文由AnonyStar 發布,可轉載但需宣告原文出處,
仰慕「優雅編碼的藝術」 堅信熟能生巧,努力改變人生
歡迎關注微信公賬號 :云棲簡碼 獲取更多優質文章
更多文章關注筆者博客 :云棲簡碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/167803.html
標籤:Java
上一篇:黑菜菌的JAVA學習筆記
