舒適提示:內容較多建議收藏閱讀,大約須要5分鐘。java
代碼可在GitHub中閱讀:歡迎star。github.com/UniqueDong/…git
在經常使用的23種設計模式中其實面沒有委派模式(delegate)的影子,可是在 Spring 中委派模式確實用的比較多的一種模式,Spring MVC 框架中的DispatcherServlet其實就用到了委派模式github
其實我我的的理解就是一個特殊的靜態代理模式,只不過加入了策略模式,咱們看下面的圖。算法
策略模式的環境上下文角色只有一個策略抽象的引用,而後根據條件設置對應的策略調用。而委託持有全部的策略,根據條件去將請求委託到對應的實現類中執行。設計模式
咱們經過一個簡單例子來看看策略模式:它只只有一個策略的引用,根據不一樣場景切換策略。bash
假設如今要設計一個販賣各種書籍的電子商務網站的購物車系統。app
一個最簡單的狀況就是把全部貨品的單價乘上數量,可是實際狀況確定比這要複雜。框架
好比,本網站可能對全部的高級會員提供每本20%的促銷折扣;對中級會員提供每本10%的促銷折扣;對初級會員沒有折扣。ide
根據描述,折扣是根據如下的幾個算法中的一個進行的:函數
代碼實現以下:定義抽象策略角色
/** * 抽象折扣類(抽象策略(Strategy)角色) */
public interface MemberStrategy {
/** * 計算圖書的價格 * @param booksPrice 原書價格 * @return 打折後的價格 */
double calcPrice(double booksPrice);
}
複製代碼
而後定義咱們針對不一樣會員的折扣算法實現
/** * 具體策略(ConcreteStrategy)角色 * 初級會員折扣具體策略 */
public class PrimaryMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("對初級會員沒有打折");
return booksPrice;
}
}
/** * 中級會員折扣策略 */
public class IntermediteMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("對於中級會員的折扣爲10%");
return booksPrice * 0.9;
}
}
/** * 高級會員折扣策略 */
public class AdvanceMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
return booksPrice * 0.8;
}
}
複製代碼
最後咱們還需定義個策略上下文角色,它只有一個抽象策略的引用。
/** * 環境(Context)角色:持有一個Strategy的引用。 * Created by unique on 2017/6/1. */
public class PriceContext {
/** * 持有一個具體的策略對象 */
private MemberStrategy memberStrategy;
/** * 構造方法,傳入一個具體策略 * @param memberStrategy */
public PriceContext(MemberStrategy memberStrategy) {
this.memberStrategy = memberStrategy;
}
/** * 計算圖書的價格 * @param booksPrice * @return */
public double calcPrice(double booksPrice) {
return memberStrategy.calcPrice(booksPrice);
}
public void setMemberStrategy(MemberStrategy memberStrategy) {
this.memberStrategy = memberStrategy;
}
}
複製代碼
最後咱們編寫客戶端來模擬
public class Clinet {
public static void main(String[] args) {
//選擇並建立所要的策略
MemberStrategy strategy = new AdvanceMemberStrategy();
//建立環境
PriceContext context = new PriceContext(strategy);
double booksPrice = 500.98;
double price = context.calcPrice(booksPrice);
System.out.println("圖書的原價:" + booksPrice + "打折後的最終價格:" + price);
System.out.println("----切換會員----");
strategy = new PrimaryMemberStrategy();
context.setMemberStrategy(strategy);
price = context.calcPrice(booksPrice);
System.out.println("圖書的原價:" + booksPrice + "打折後的最終價格:" + price);
}
}
複製代碼
打印結果以下所示:
書的原價:500.98打折後的最終價格:400.78400000000005
----切換會員----
對初級會員沒有打折
圖書的原價:500.98打折後的最終價格:500.98
複製代碼
如今咱們回到委派模式,其實跟策略模式很像,區別就是委派模式的 DispatcherServlet 持有全部的委託類引用。
假設如今 Boss 點子來了想作一個根據手機外殼來改變 app 主題樣式功能。這個時候就把任務交給了產品經理 ,產品經理就找來程序猿委託開發小哥哥去分工實現。這樣Boss就是一個請求,而產品經理就是一個 dispatcherSevlet 。
boss把任務給 leader, 而 leader 作了一個任務的分配和調度的工做,本身沒有作工做,而是把具體工做交給具體的執行者去作。
代碼實現以下
首先定義咱們的任務執行角色,以及各自分工任務的程序猿
/** * 執行的接口 */
public interface IExcuter {
void execute(String command);
}
/** * 程序猿A執行的工做 */
public class ExcuterA implements IExcuter {
@Override
public void execute(String command) {
System.out.println("員工A 開始作" + command + "的工做");
}
}
/** * 程序猿B執行的任務 */
public class ExcuterB implements IExcuter {
@Override
public void execute(String command) {
System.out.println("員工B 開始作" + command + "的工做");
}
}
複製代碼
接着定義咱們的 產品經理
/** * @description: leader 委派者 任務分發的做用 * @ModificationHistory who when What **/
public class LeaderDispatch {
private Map<String, IExcuter> targets = new HashMap<String, IExcuter>();
public Leader() {
targets.put("識別顏色", new ExcuterA());
targets.put("切換主題", new ExcuterB());
}
public void dispatch (String command) {
//根據指令委託到對應的執行者
targets.get(command).execute(command);
}
}
複製代碼
最後咱們模擬boss發送指令實現功能
public class Boss {
public static void main(String[] args) {
LeaderDispatch leader = new LeaderDispatch();
//看上去好像是咱們的項目經理在幹活
//但實際幹活的人是普通員工
//這就是典型,幹活是個人,功勞是你的
leader.execute("識別顏色");
leader.execute("切換主題");
}
}
複製代碼
最後咱們查看打印結果
員工B 開始作登陸的工做
員工A 開始作加密的工做
複製代碼
經過此文咱們從新複習了策略模式,經過策略模式演化出委託模式。
Spring MVC框架中的DispatcherServlet其實就是用到的委派模式,針對以前的MVC執行流程沒法理解的HandlerMapping其實就是這裏的項目經理維護的各個員工的信息。
上述實例中,爲了簡單,直接在構造函數中維護了相關實例的引用,可是在具體的HandlerMapping 中,這一步顯然要複雜的多。
關注、轉發、點贊收藏,個人兩小時編寫換你一秒的隨手關注、轉發、點贊收藏