今天開始咱們專題的第七課了。本章節將介紹:你寫的代碼中是否以爲很臃腫,程序中有大量的if...else,想優化代碼,精簡程序邏輯,提高代碼的可讀性,這章節將介紹如何經過委派模式、策略模式讓你代碼更優雅,消除程序大量冗餘的代碼。本章節參考資料書籍《Spring 5核心原理》中的第一篇 Spring 內功心法(Spring中經常使用的設計模式)(沒有電子檔,都是我取其精華並結合本身的理解,一個字一個字手敲出來的)。java
委派模式不屬於GOF23種設計模式中。委派模式(Delegate Pattern)的基本做用就是負責任務的調用和分配任務,跟代理模式很像,能夠看作是一種特殊狀況下的靜態代理的全權代理,可是代理模式注重過程,而委派模式注重結果。委派模式在Spring中應用很是多,你們經常使用的DispatcherServlet其實就是用到了委派模式。現實生活中也常有委派的場景發生,例如:老闆(Boss)給項目經理(Leader)下達任務,項目經理會根據實際狀況給每一個員工派發工做任務,待員工把工做任務完成以後,再由項目經理彙報工做進度和結果給老闆。咱們用代碼來模擬下這個業務場景,先來看一下類圖:算法
建立員工接口設計模式
package com.study.demo2; /** * @ClassName IEmployee * @Deacription 員工接口 * @Author wang.zhong.yuan * @Date 2020/7/9 16:36 * @Version 1.0 **/ public interface IEmployee { /** * 須要作的工做 * @param command */ void doingSomeThing(String command); }
員工A實現類安全
package com.study.demo2; /** * @ClassName EmployeeA * @Deacription 員工A * @Author wang.zhong.yuan * @Date 2020/7/9 16:38 * @Version 1.0 **/ public class EmployeeA implements IEmployee { public void doingSomeThing(String command) { System.out.println("我是員工A,須要作:"+command); } }
員工B實現類微信
package com.study.demo2; /** * @ClassName EmployeeB * @Deacription 員工B * @Author wang.zhong.yuan * @Date 2020/7/9 16:48 * @Version 1.0 **/ public class EmployeeB implements IEmployee { public void doingSomeThing(String command) { System.out.println("我是員工B,我要作:"+command); } }
領導類ide
package com.study.demo2; import java.util.HashMap; import java.util.Map; /** * @ClassName Leader * @Deacription 領導類 * @Author wang.zhong.yuan * @Date 2020/7/9 16:51 * @Version 1.0 **/ public class Leader implements IEmployee { private Map<String,IEmployee> underling = new HashMap<String, IEmployee>(); public Leader() { underling.put("註冊功能",new EmployeeA()); underling.put("登錄功能",new EmployeeB()); } /** * 本身不作事,委派給對應的員工去作 * @param command */ public void doingSomeThing(String command) { underling.get(command).doingSomeThing(command); } }
建立BOSS類,安排工做給Leader測試
package com.study.demo2; /** * @ClassName Boss * @Deacription TODO * @Author 19054253 * @Date 2020/7/9 17:03 * @Version 1.0 **/ public class Boss { public void command(String command, Leader leader){ leader.doingSomeThing(command); } //測試功能 public static void main(String[] args) { //客戶請求(Boss)、委派者(Leader)、被被委派者(Target) //委派者要持有被委派者的引用 //代理模式注重的是過程, 委派模式注重的是結果 //策略模式注重是可擴展(外部擴展),委派模式注重內部的靈活和複用 //委派的核心:就是分發、調度、派遣 //委派模式:就是靜態代理和策略模式一種特殊的組合 Boss boss = new Boss(); Leader leader = new Leader(); boss.command("登錄功能",leader); } }
輸出結果微信支付
經過上面的代碼,生動地還原了項目經理分配工做的業務場景,也是委派模式的生動體現。優化
策略模式(Strategy Pattern)是指定義了算法家族、分別封裝起來,讓它們之間能夠互相替換,此模式讓算法的變化不會影響到使用算法的用戶。假如系統中有不少類,而他們的區別僅僅在於他們的行爲不一樣。一個系統須要動態地在幾種算法中選擇一種,均可以用策略模式實現。ui
一個常見的應用場景就是你們在下單支付時會提示選擇支付方式,若是用戶未選,系統也會默認好推薦的支付方式進行結算。來看一下類圖,下面咱們用策略模式來模擬此業務場景:
建立支付狀態類:
package com.study.demo3; /** * @ClassName PayState * @Deacription 支付狀態 * @Author wang * @Date 2020/7/9 17:48 * @Version 1.0 **/ public class PayState { private int code; private Object data; private String message; public PayState(int code, Object data, String message) { this.code = code; this.data = data; this.message = message; } @Override public String toString() { return "PayState{" + "code=" + code + ", data=" + data + ", message='" + message + '\'' + '}'; } }
建立支付接口
package com.study.demo3; /** * @ClassName Payment * @Deacription 支付渠道 * @Author wang * @Date 2020/7/9 19:12 * @Version 1.0 **/ public interface IPayment { /** * 獲取支付類型 * @return */ String getName(); /** * 查詢餘額 * @param uid * @return */ double queryBalance(String uid); /** * 支付 * @param uid * @param amount * @return */ PayState pay(String uid,double amount); }
建立支付抽象類,完成一些通用的代碼:
package com.study.demo3; /** * @ClassName AbstractPayment * @Deacription 支付抽象類 * @Author wang * @Date 2020/7/9 19:16 * @Version 1.0 **/ public abstract class AbstractPayment implements IPayment{ public PayState pay(String uid, double amount) { if (queryBalance(uid) < amount){ return new PayState(-1,"支付失敗","餘額不足"); } return new PayState(200,"支付成功","共計支付:"+amount); } }
建立阿里支付渠道
package com.study.demo3; /** * @ClassName AliPay * @Deacription 支付寶支付 * @Author wang * @Date 2020/7/9 19:20 * @Version 1.0 **/ public class AliPay extends AbstractPayment { public String getName() { return "支付寶支付"; } public double queryBalance(String uid) { return 500; } }
建立京東支付渠道
package com.study.demo3; /** * @ClassName JDPay * @Deacription 京東支付 * @Author wang * @Date 2020/7/9 19:22 * @Version 1.0 **/ public class JDPay extends AbstractPayment { public String getName() { return "京東支付"; } public double queryBalance(String uid) { return 900; } }
建立微信支付渠道
package com.study.demo3; /** * @ClassName WXPay * @Deacription 微信支付 * @Author wang * @Date 2020/7/9 19:23 * @Version 1.0 **/ public class WXPay extends AbstractPayment { public String getName() { return "微信支付"; } public double queryBalance(String uid) { return 256; } }
package com.study.demo3; /** * @ClassName Order * @Deacription 訂單類 * @Author wang * @Date 2020/7/9 19:35 * @Version 1.0 **/ public class Order { private String uid; private String orderId; private double amount; public Order(String uid,String orderId,double amount){ this.uid = uid; this.orderId = orderId; this.amount = amount; } //完美地解決了 switch 的過程,不須要在代碼邏輯中寫 switch 了 //更不須要寫 if else if public PayState pay(){ return pay(PayStrategy.DEFAULT_PAY); } public PayState pay(String payKey){ IPayment payment = PayStrategy.get(payKey); System.out.println("歡迎使用" + payment.getName()); System.out.println("本次交易金額爲:" + amount + ",開始扣款..."); return payment.pay(uid,amount); } //測試代碼 public static void main(String[] args) { Order order = new Order("123", "AB123", 400); //這個值是在支付的時候才決定用哪一個值 用戶本身決定 order.pay("AliPay"); } }
輸出結果:
但願經過你們耳熟能詳的業務場景來舉例,讓小夥伴們更深入地理解策略模式。
優勢:
一、策略模式符合開閉原則。
二、避免使用多重條件轉移語句,如if...else...語句、switch語句
三、使用策略模式能夠提升算法的保密性和安全性。
缺點: 一、客戶端必須知道全部的策略,而且自行決定使用哪個策略類。 二、代碼中會產生很是多策略類,增長維護難度。