Spring中常見的設計模式——策略模式


  策略模式(Strategy Pattern)是指定義了算法家族病分別封裝起來,讓他們之間可以互相替換,此模式是的算法的變化不會影響使用算法的用戶。

一、策略模式的應用場景

  策略模式的應用場景如下:

  • 系統中有很多類,而他們的區別僅僅在於行為不同。
  • 一個系統需要動態的在幾種算法中選擇一種

二、用策略模式實現選擇支付方式的業務場景

  一個常見的應用場景就是大家在支付時會提示選擇支付方式,如果用戶未選,系統會使用默認的支付方式進行結算。下面我們用策略模式來模擬此業務場景:

/**
 * 定義支付規范和支付邏輯
 */
public abstract class Payment {

    //支付類型
    public abstract String getName();

    //查詢余額
    protected abstract double queryBalance(String uid);

    //扣款支付
    public PayState pay(String uid, double amount) {
        if (queryBalance(uid) < amount) {
            return new PayState(500, "支付失敗", "余額不足");
        }
        return new PayState(200, "支付成功", "支付金額:" + amount);
    }
}

  扣款支付邏輯簡單做一下:

/**
 * 支付邏輯
 */
public class PayState {
    private int code;
    private Object data;
    private String msg;

    public PayState(int code, String msg, String data) {
        this.code = code;
        this.data = data;
        this.msg = msg;
    }

    public String toString() {
        return ("支付狀態:[" + code + "]," + msg + ",交易詳情:" + data);
    }
}

  定義兩種支付方式:

/**
 * 支付寶
 */
public class AliPay extends Payment {
    @Override
    public String getName() {
        return "支付寶";
    }

    @Override
    protected double queryBalance(String uid) {
        return 900;
    }
}

/**
 * 微信支付
 */
public class WechatPay extends Payment {
    @Override
    public String getName() {
        return "微信支付";
    }

    @Override
    protected double queryBalance(String uid) {
        return 256;
    }
}

  支付策略管理類

/**
 * 支付策略管理類
 */
public class PayStrategy {
    public static final String ALI_PAY = "AliPay";
    public static final String WECHAT_PAY = "WechatPay";
    public static final String DEFAULT_PAY = ALI_PAY;

    private static Map<String, Payment> payStrategy = new HashMap<>();

    static {
        payStrategy.put(ALI_PAY, new AliPay());
        payStrategy.put(WECHAT_PAY, new WechatPay());
    }

    public static Payment get(String payKey) {
        if (!payStrategy.containsKey(payKey)) {
            return payStrategy.get(DEFAULT_PAY);
        }
        return payStrategy.get(payKey);
    }
}

  創建訂單:訂單支付時因為支付方式已經在集合內並且可以通過key得到,所以不用switch 和if else進行贅述

/**
 * 訂單類
 */
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) {
        Payment payment = PayStrategy.get(payKey);
        System.out.println("歡迎使用:" + payment.getName());
        System.out.println("本次交易金額為:" + amount + ",扣款中...");
        return payment.pay(uid, amount);
    }
}

  測試類:

public class PayStrategyTest {
    public static void main(String[] args) {
        //創建訂單
        Order order = new Order("1", "202001080001", 324.45);

        //選擇支付方式:支付寶支付
        System.out.println(order.pay(PayStrategy.ALI_PAY));
    }
}

三、策略模式在源碼中的體現

1.JDK中的應用

  首先看比較常見的比較器——Compare接口,常用的compare()方法就是常見的策略模式的抽象實現,Comparator接口下面有非常多的實現類,我們把Comparator接口作為傳入實現排序策略例如:

public static <T> void parallelSort(T[] a, Comparator<? super T> cmp) {
        if (cmp == null)
            cmp = NaturalOrder.INSTANCE;
        int n = a.length, p, g;
        if (n <= MIN_ARRAY_SORT_GRAN ||
            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
            TimSort.sort(a, 0, n, cmp, null, 0, 0);
        else
            new ArraysParallelSortHelpers.FJObject.Sorter<T>
                (null, a,
                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
                 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
                 MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
    }

  還有TreeMap類的構造方法:

    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

2.Spring源碼中的應用

  Spring的初始化采用了策略模式,不同類型的類采用不同的初始化策略。

public interface InstantiationStrategy {
    Object instantiate(RootBeanDefinition var1, String var2, BeanFactory var3) throws BeansException;

    Object instantiate(RootBeanDefinition var1, String var2, BeanFactory var3, Constructor<?> var4, Object... var5) throws BeansException;

    Object instantiate(RootBeanDefinition var1, String var2, BeanFactory var3, Object var4, Method var5, Object... var6) throws BeansException;
}

四、策略模式的優缺點

 策略模式的優點如下:

  • 策略模式符合開閉原則。
  • 策略模式可避免使用多重條件語句,如switch if else。
  • 使用策略模式可以提高算法的保密性和安全性。

 策略模式的缺點如下:

  • 客戶端必須知道所有的策略,並且自行決定使用哪一個策略類。
  • 代碼中會產生非常多的策略類,增加了代碼的維護難度。

五、委派模式與策略模式綜合應用

  委派模式:DispatcherServlet 根據url對應Controller 用的是if else, 應該將對應關系放入容器中,利用URL找到對應的Controller,這樣做成策略模式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM