玩轉策略模式

寒露君發表於2018-11-05

策略模式

原始碼地址

定義

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

場景

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

舉例: 在一些外部閘道器,如銀行閘道器設計時,因直連模式時會接入多個銀行,這些銀行的具體報文封裝邏輯、解析邏輯、業務邏輯不同(實現ConcreteStrategy),但其都可抽象為共用的閘道器處理邏輯(介面Strategy);為減少呼叫方對實現的依賴關係、便於接入其他銀行、共用程式碼邏輯的複用,可採用策略模式進行設計;

結構

  • Strategy

多個類似行為的抽象,Context所依賴的介面

  • ConcreteStrategy

Strategy的具體實現,為Context提供具體邏輯實現

  • Context

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

  • 流程描述

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

玩轉策略模式

推薦搭配

工廠模式、模板方法

程式碼實現

  • 簡單策略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);
        //呼叫,外部對內部無感知,無依賴
        //Trans內部只依賴行為介面,不依賴實現,可動態改變其行為實現
        trans.transfer(invocation);
    }
}
複製程式碼

簡單演示動態行為切換

/**
 * @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仍有很大的優化空間,需要大家發散思維;

測試程式碼

/**
 * 測試
 */
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);
    }
}
複製程式碼

相關文章