策略模式與模版模式的區別與應用


本文為博主原創,未經允許不得轉載:

  最近在做項目的優化,由於項目在早期缺乏規划,在開發過程中,對於某一個業務的不同類型判斷,增加了很多 if else ,代碼的健壯性變得很差。

所以考慮使用設計模式中的策略模式與模版模式進行開發中的代碼設計。且由於在使用過程中策略模式與模版模式經常一起使用,所以對這兩種設計模式

進行一起整理記錄下。

 

  1.模版模式:

    模版模式的定義:模板方法模式定義了一個算法的步驟,並允許子類別為一個或多個步驟提供其實踐方式。讓子類別在不改變算法架構的情況下,重新定義算法中的某些步驟。

    模版模式屬於行為型設計模式,其意圖是在一個方法里實現一個算法,並定義延遲算法的某些步驟,從而讓其他類重新定義他們。

    項目中經常使用的RestTemplate,JdbcTemplate,RedisTemplate等都采用了模版模式的設計模式,因為在操作資源的時候,經常會涉及到打開資源鏈接

  關閉資源連接等,且為公用的模式,所以采用模版模式,然后將其定義為一個算法骨架,通過子類或實現類來實現算法的具體實現。

    example:

    定義一個模版:

public abstract class AbstractDataSourceTemplate {
    /**
     * 開啟連接
     */
    abstract void open();

    /**
     * 執行操作
     */
    abstract void execute();

    /**
     * 關閉連接
     */
    abstract void close();

    /**
     * 模版方法
     */
    public final void run() {
        open();
        execute();
        close();
    }
}

    通過上述模版實現JdbcTemplate  與 RedisTemplate 

public class RedisDataSourceTemplate extends AbstractDataSourceTemplate {
    /**
     * 開啟連接
     */
    @Override
    void open() {
        System.out.println("開啟redis連接...");
    }

    /**
     * 執行操作
     */
    @Override
    void execute() {
        System.out.println("操作redis...");
    }

    /**
     * 關閉連接
     */
    @Override
    void close() {
        System.out.println("關閉redis連接...");
    }
}

JdbcTemplate  ::

public class JdbcDataSourceTemplate extends AbstractDataSourceTemplate {
    /**
     * 開啟連接
     */
    @Override
    void open() {
        System.out.println("開啟jdbc連接...");
    }

    /**
     * 執行操作
     */
    @Override
    void execute() {
        System.out.println("操作jdbc...");
    }

    /**
     * 關閉連接
     */
    @Override
    void close() {
        System.out.println("關閉jdbc連接...");
    }
}

使用

//jdbc模版
        AbstractDataSourceTemplate template = new JdbcDataSourceTemplate();
        template.run();
        System.out.println("----------------");
        //redis模版
        AbstractDataSourceTemplate template1 = new RedisDataSourceTemplate();
        template1.run();

總結

  • 封裝不可變部分,擴展可變部分
  • 提取公共代碼,便於維護
  • 行為由父類控制骨架/算法,子類實現
  • 對每個不同的實現都需要定義一個子類,這會導致類的個數增加,系統更加龐大,設計也更加抽象
  • 父類中的抽象方法由子類實現,子類執行的結果會影響父類的結果,這導致一種反向的控制結構,它提高了代碼閱讀的難度

 2.策略模式:

    策略模式的應用比模版模式的應用場景更為常見。我們在開發過程中,經常會使用 if .. else if ( )  或 switch 。。 case。。等進行同一個業務的不同場景或類型判斷。

  比如進行權限校驗判斷時,判斷當前管理員是 超級管理員:userType ==1,如果是二級管理員  userType == 2....等等。這些場景都可以使用策略模式進行開發優化,可以避免

  很長的 if else 判斷。

    策略模式的定義: 

  策略模式(Strategy Pattern)屬於對象的行為模式。其用意是針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們可以相互替換。
  策略模式使得算法可以在不影響到客戶端的情況下發生變化。
  其主要目的是通過定義相似的算法,替換if
else 語句寫法,並且可以隨時相互替換。

    在其他博客中找到一個很好的場景,是支付場景,通過策略模式區分支付寶,銀行卡,點券支付的場景。

    

package strategy;

public interface PayStrategy {
    String selectPayWay(Integer paycode);
}

 

  規定具體策略行為

package strategy;

public class PayContext {

    private PayStrategy payStrategy;

    public String selectPayWay(Integer payCode){
        payStrategy =  StrategyFactory.getInstance().create(payCode);
        return payStrategy.selectPayWay(payCode);
    }

    public PayStrategy getPayStrategy() {

        return payStrategy;
    }

    public void setPayStrategy(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }
}

 

支付寶付款實現類

package strategy.paystrategy;

import strategy.PayStrategy;

public class ALPayStrategy implements PayStrategy {

    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "支付寶支付成功";
    }
}

 

銀行卡支付實現類

package strategy.paystrategy;

import strategy.PayStrategy;

public class CardPayStrategy implements PayStrategy {
    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "銀行卡支付成功";
    }
}

 

微信支付實現類

package strategy.paystrategy;

import strategy.PayStrategy;

public class WeChatPayStrategy implements PayStrategy {

    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "微信支付成功";
    }

}

 

創建策略類的工廠

package strategy;

import pay.PayWayEnum;
import strategy.paystrategy.ALPayStrategy;
import strategy.paystrategy.CardPayStrategy;
import strategy.paystrategy.PointCouponPayStrategy;
import strategy.paystrategy.WeChatPayStrategy;

import java.util.HashMap;
import java.util.Map;

public class StrategyFactory {

    private static StrategyFactory factory = new StrategyFactory();

    private StrategyFactory(){}

    private static Map strategyMap = new HashMap<>(16);

    static {
        strategyMap.put(PayWayEnum.AL_PAY.getCode(),new ALPayStrategy());
        strategyMap.put(PayWayEnum.WEICHAT_PAY.getCode(),new WeChatPayStrategy());
        strategyMap.put(PayWayEnum.CARD_PAY.getCode(),new CardPayStrategy());
        strategyMap.put(PayWayEnum.PONIT_COUPON_PAY.getCode(),new PointCouponPayStrategy());
    }

    public PayStrategy create(Integer payCode){
        return (PayStrategy) strategyMap.get(payCode);
    }

    public static StrategyFactory getInstance(){
        return factory;
    }

}

 

實現客戶端

package strategy;

public class Client {

    public static void main(String[] args) {
        PayContext payContext = new PayContext();
        System.out.println(payContext.selectPayWay(100));
    }
}

 

最后在貼一個枚舉類

package pay;

public enum PayWayEnum {

    /**微信支付*/
    WEICHAT_PAY("微信支付",100),
    /**支付寶支付*/
    AL_PAY("支付寶支付",101),
    /**銀行卡支付*/
    CARD_PAY("銀行卡支付",102),
    /**點券支付*/
    PONIT_COUPON_PAY("點券支付",103);

    private String msg;
    private Integer code;

    PayWayEnum(String msg, Integer code) {
        this.msg = msg;
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public Integer getCode() {
        return code;
    }
}

  從上面代碼中,我們可以看到,我們完全消除了對狀態碼進行判斷的那些if…else的冗余代碼,取而代之是直接由客戶端決定使用哪種算法,

然后交由上下文獲取結果。極大的增強的了擴展性,隱藏了內部實現的細節,當然我們也可以看到,策略模式由於獨立策略的實現,

也使得系統內部增加了很多策略,對客戶端來必須知道這些策略類實現的是那些策略,而且需要知道具體的策略條件。

  然而在實際的生產環境中我們可能不會像示例代碼這樣干,在實際的生產環境中我們一般會結合spring來對我們所需的策略進行操作,

這邊我可以給大家有個具體的思路,大家可以通過這個思路來想想,自己在實際生產環境會怎樣操作

1.首先和上面代碼一樣定義一個Strategy接口,其中有一個operation的函數交給具體業務去實現
2.根據自己的業務,會擁有很多的策略類實現該接口;將這些類注冊到spring Bean容器中提供使用。
3。通過客戶端傳值,從spring容器中獲取Strategy實例
4.最終來執行operation函數

 

參考博客:https://blog.csdn.net/qq1037893644/article/details/102681593

 


免責聲明!

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



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