玩轉(zhuǎn)策略模式

策略模式

源碼地址

定義

定義了算法族(一組行為),分別封裝起來(封裝實現(xiàn)),讓他們之間可以相互替換(擴展),此模式讓算法的變化(擴展)獨立與使用算法的客戶(解耦);

場景

  • Strategy描述一組概念相同卻行為不同(一個接口卻實現(xiàn)不同)的相關類;
  • Strategy的使用客戶不應該知道其具體實現(xiàn)(解耦),避免暴露復雜的、與具體策略相關的數(shù)據(jù)結(jié)構(gòu);
  • 一個類定義多種行為,避免這些行為以if-else的形式出現(xiàn)在此類中,減少對實現(xiàn)細節(jié)的依賴;

舉例: 在一些外部網(wǎng)關,如銀行網(wǎng)關設計時,因直連模式時會接入多個銀行,這些銀行的具體報文封裝邏輯、解析邏輯、業(yè)務邏輯不同(實現(xiàn)ConcreteStrategy),但其都可抽象為共用的網(wǎng)關處理邏輯(接口Strategy);為減少調(diào)用方對實現(xiàn)的依賴關系、便于接入其他銀行、共用代碼邏輯的復用,可采用策略模式進行設計;

結(jié)構(gòu)

  • Strategy

多個類似行為的抽象,Context所依賴的接口

  • ConcreteStrategy

Strategy的具體實現(xiàn),為Context提供具體邏輯實現(xiàn)

  • Context

上下文(客戶),一個具有多種行為的類,持有strategy引用

  • 流程描述

Context 與Strategy關系為一對多,Strategy與ConcreteStrategy關系為一對多

image

推薦搭配

工廠模式、模板方法

代碼實現(xiàn)

  • 簡單策略DEMO

測試代碼

public class TransTest extends NnnToolsApplicationTests {

    @Autowired
    private Trans trans;
    @Test
    public void testTrans(){
        TransDO transDO = new TransDO();
        Invocation invocation = new Invocation();
        invocation.setBizType("N00001");
        invocation.setParam(transDO);
        //調(diào)用,外部對內(nèi)部無感知,無依賴
        //Trans內(nèi)部只依賴行為接口,不依賴實現(xiàn),可動態(tài)改變其行為實現(xiàn)
        trans.transfer(invocation);
    }
}

簡單演示動態(tài)行為切換

/**
 * @author hanlujun
 */
@Service
public class TransImpl implements Trans {
    
    @Autowired
    private Map<String,Validator> validators;

    /**
     * 交易操作
     * @param var1
     * @return
     */
    @Override
    public Result transfer(Invocation var1) {
        //**變化的行為**
        //獲取對應業(yè)務類型的校驗(如權(quán)限校驗、非空校驗、賬戶校驗等)
        Validator validator = validators.get(var1.getBizType());
        if(Objects.nonNull(validator)){
            //校驗
            validator.validation(var1.getParam());
        }
        //執(zhí)行對應業(yè)務類型的業(yè)務邏輯
        return accountOperation(var1).doTransfer(var1);
    }
    
    /**
    * 測試
    */
    public TransOperation accountOperation(Invocation var1){
        // **變化的行為**
        return SpringContextUtil.getBean(var1.getBizType(), TransOperation.class);
    }
}

  • 進階策略DEMO

借鑒之前老師的寫法來演示并做了稍微改動,demo簡單描述了策略模式是如何實現(xiàn)可復用、可擴展、可維護的OO思想;
另外此demo仍有很大的優(yōu)化空間,需要大家發(fā)散思維;

測試代碼

/**
 * 測試
 */
public class TransTest extends NnnToolsApplicationTests {
    @Autowired
    private StrategyFactory strategyFactory;

    public void testTrans(){
        Context context = strategyFactory.makeDecision("N00001");
        context.execute("N00001","{}");
    }
}


策略接口

/**
 * 多個類似行為的抽象,Context所依賴的接口
 */
public interface IStrategy {

    Response execute(String code, String jsonBody);
}

策略接口與具體實現(xiàn)結(jié)合并結(jié)合模板方法

/**
 * 多個類似行為的抽象,Context所依賴的接口,具體策略有子類實現(xiàn)
 */
@Slf4j
public abstract class AbstractStrategy implements IStrategy{

    @Autowired
    private Map<String, Validator> validators;

    @Override
    public Response execute(String code , String jsonBody) {
      //獲取對應業(yè)務類型的校驗(如權(quán)限校驗、非空校驗、賬戶校驗等)
        Validator validator = validators.get(code);
        if(Objects.nonNull(validator)){
            //校驗
            validator.validation(jsonBody);
        }
        //執(zhí)行對應業(yè)務類型的業(yè)務邏輯
        return doTransfer(code);
    }
    
     /**
     * 具體實現(xiàn)由子類決定
     * @param code
     * @return
     */
    protected abstract Response doTransfer(String code);

}

策略模式中的客戶Context

/**
 * 上下文(客戶),一個具有多種行為的類,持有strategy引用
 */
public class Context {

    private IStrategy strategy;

    private Context(IStrategy strategy){
        this.strategy = strategy;
    }

    public static Context getInstance(IStrategy strategy){
      return new Context(strategy);
    }

    /**
     * 執(zhí)行策略
     * @param code
     * @param jsonBody
     * @return
     */
    public Response execute(String code, String jsonBody) {
        return strategy.execute(code,jsonBody);
    }
}

/**
 * 策略工廠
 */
public interface IStrategyFactory {

    Context makeDecision(String code);
}

推薦搭配:工廠類

/**
 * 策略工廠
 */
@Component
public class StrategyFactory implements IStrategyFactory {
    @Override
    public Context makeDecision(String code) {
        String serviceName =BizTypeEnums.getServiceByCode(code);
        IStrategy strategy = SpringContextUtil.getBean(serviceName);
        return Context.getInstance(strategy);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 設計模式概述 在學習面向?qū)ο笃叽笤O計原則時需要注意以下幾點:a) 高內(nèi)聚、低耦合和單一職能的“沖突”實際上,這兩者...
    彥幀閱讀 3,888評論 0 14
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • [Java策略模式(Strategy模式) 之體驗] public class Client { } 測試輸出結(jié)果...
    堅持編程_lyz閱讀 305評論 0 0
  • 本文僅僅為入門,高手勿噴。 實際工作中,我們總會遇到類似如下的需求:某支付系統(tǒng)接入以下幾種商戶進行充值:易寶網(wǎng)易,...
    JarvanMo閱讀 14,372評論 14 26
  • 一直以來,我思索著一個奇怪又無聊的冷知識:從遠古到現(xiàn)代,從前世到今生,人類縱橫幾萬年至今,難道就沒有相同的兩個人出...
    林春生閱讀 582評論 0 2

友情鏈接更多精彩內(nèi)容