玩轉策略模式

策略模式

源碼地址

定義

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

場景

  • Strategy描述一組概念相同卻行爲不一樣(一個接口卻實現不一樣)的相關類;
  • Strategy的使用客戶不該該知道其具體實現(解耦),避免暴露覆雜的、與具體策略相關的數據結構;
  • 一個類定義多種行爲,避免這些行爲以if-else的形式出如今此類中,減小對實現細節的依賴;

舉例: 在一些外部網關,如銀行網關設計時,因直連模式時會接入多個銀行,這些銀行的具體報文封裝邏輯、解析邏輯、業務邏輯不一樣(實現ConcreteStrategy),但其均可抽象爲共用的網關處理邏輯(接口Strategy);爲減小調用方對實現的依賴關係、便於接入其餘銀行、共用代碼邏輯的複用,可採用策略模式進行設計;json

結構

  • Strategy

多個相似行爲的抽象,Context所依賴的接口bash

  • ConcreteStrategy

Strategy的具體實現,爲Context提供具體邏輯實現數據結構

  • Context

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

  • 流程描述

Context 與Strategy關係爲一對多,Strategy與ConcreteStrategy關係爲一對多測試

推薦搭配

工廠模式、模板方法優化

代碼實現

  • 簡單策略DEMO

測試代碼ui

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);
        //調用,外部對內部無感知,無依賴
        //Trans內部只依賴行爲接口,不依賴實現,可動態改變其行爲實現
        trans.transfer(invocation);
    }
}
複製代碼

簡單演示動態行爲切換this

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

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

複製代碼
  • 進階策略DEMO

借鑑以前老師的寫法來演示並作了稍微改動,demo簡單描述了策略模式是如何實現可複用、可擴展、可維護的OO思想;
另外此demo仍有很大的優化空間,須要你們發散思惟;spa

測試代碼

/**
 * 測試
 */
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);
}

複製代碼

策略接口與具體實現結合並結合模板方法

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

    @Autowired
    private Map<String, Validator> validators;

    @Override
    public Response execute(String code , String jsonBody) {
      //獲取對應業務類型的校驗(如權限校驗、非空校驗、帳戶校驗等)
        Validator validator = validators.get(code);
        if(Objects.nonNull(validator)){
            //校驗
            validator.validation(jsonBody);
        }
        //執行對應業務類型的業務邏輯
        return doTransfer(code);
    }
    
     /**
     * 具體實現由子類決定
     * @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);
    }

    /**
     * 執行策略
     * @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);
    }
}
複製代碼
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息