大型Java進階專題(七) 設計模式之委派模式與策略模式

前言

​ 今天開始咱們專題的第七課了。本章節將介紹:你寫的代碼中是否以爲很臃腫,程序中有大量的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語句
三、使用策略模式能夠提升算法的保密性和安全性。

缺點: 一、客戶端必須知道全部的策略,而且自行決定使用哪個策略類。 二、代碼中會產生很是多策略類,增長維護難度。

相關文章
相關標籤/搜索