策略模式
原始碼地址
定義
定義了演算法族(一組行為),分別封裝起來(封裝實現),讓他們之間可以相互替換(擴充套件),此模式讓演算法的變化(擴充套件)獨立與使用演算法的客戶(解耦);
場景
- 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);
}
}
複製程式碼