通用政策模式實作 — Flea Strategy
1. 概述
政策模式(Strategy Pattern)作為一種軟體設計模式,用來實作對象的某個行為,該行為在不同的場景中擁有不同的實作邏輯。它定義了一組算法,同時将這些算法封裝起來,并使它們之間可以互換。
常用的政策模式有如下三個角色:
-
抽象政策角色 — Strategy
抽象政策類,通常為一個接口,其中定義了某個政策行為【即政策算法辨別】。
-
具體政策角色 — ConcreteStrategy
具體政策類,實作抽象政策中的政策行為;每一個具體政策類即代表一種政策算法。
-
上下文角色 — Context
上下文類,起承上啟下封裝作用,屏蔽高層子產品對政策、算法的直接通路,封裝可能存在的變化。
本篇在上述常用的政策模式基礎上,結合門面模式和調整後的政策上下文,建構了一套通用政策模式實作。
下面我們這套通用政策模式來模拟一下各種動物的喊叫行為:
2. 參考
flea-frame-common使用之通用政策模式實作 源代碼
3. 實作
3.1 定義Flea政策接口類 — IFleaStrategy
該類定義了通用的政策行為,T 類型表示 Flea 政策執行結果對應的類型,P 類型表示 Flea 政策上下文參數。 具體代碼如下:
/**
* Flea政策接口,定義統一的政策執行方法。
*
* @param <T> Flea政策執行結果對應的類型
* @param <P> Flea政策上下文參數
* @author huazie
* @version 1.1.0
* @since 1.1.0
*/
public interface IFleaStrategy<T, P> {
/**
* 政策執行
*
* @param contextParam Flea政策上下文參數
* @return 政策執行結果對應的類型
* @throws FleaStrategyException Flea政策異常
* @since 1.1.0
*/
T execute(final P contextParam) throws FleaStrategyException;
}
3.2 定義狗叫喊聲政策類 — DogVoiceStrategy
/**
* 狗喊叫聲政策
*
* @author huazie
* @version 1.1.0
* @since 1.1.0
*/
public class DogVoiceStrategy implements IFleaStrategy<String, String> {
@Override
public String execute(String name) throws FleaStrategyException {
return "阿狗【" + name + "】正在叫喊着;汪汪汪";
}
}
3.3 定義貓叫喊聲政策類 — CatVoiceStrategy
/**
* 貓喊叫聲政策
*
* @author huazie
* @version 1.1.0
* @since 1.1.0
*/
public class CatVoiceStrategy implements IFleaStrategy<String, String> {
@Override
public String execute(String name) throws FleaStrategyException {
return "阿貓【" + name + "】正在叫喊着;喵喵喵";
}
}
3.4 定義鴨叫喊聲政策類 — DuckVoiceStrategy
/**
* 鴨喊叫聲政策
*
* @author huazie
* @version 1.1.0
* @since 1.1.0
*/
public class DuckVoiceStrategy implements IFleaStrategy<String, String> {
@Override
public String execute(String name) throws FleaStrategyException {
return "阿鴨【" + name + "】正在叫喊着;嘎嘎嘎";
}
}
3.5 定義政策上下文接口類 — IFleaStrategyContext
政策上下文接口,定義統一的政策上下文調用方法,同時可通過 getContext 擷取上下文參數,setContext 設定上下文參數。
/**
* Flea政策上下文接口,定義統一的政策上下文調用方法。
*
* @param <T> Flea政策執行結果對應的類型
* @param <P> Flea政策上下文參數
* @author huazie
* @version 1.1.0
* @since 1.1.0
*/
public interface IFleaStrategyContext<T, P> {
/**
* 政策上下文調用
*
* @param strategy 政策名稱
* @return 政策執行結果對應的類型
* @throws FleaStrategyException Flea政策異常
* @since 1.1.0
*/
T invoke(String strategy) throws FleaStrategyException;
/**
* 設定政策上下文參數
*
* @param contextParam 上下文參數對象
* @since 1.1.0
*/
void setContext(P contextParam);
/**
* 擷取政策上下文參數
*
* @return 政策上下文參數
* @since 1.1.0
*/
P getContext();
}
3.6 定義Flea抽象政策上下文類 — FleaStrategyContext
Flea 抽象政策上下文類,封裝了政策執行的邏輯,對外屏蔽高層子產品對政策的直接通路。抽象方法 init 用于初始化 Flea 政策實作 Map,該方法由Flea 政策抽象上下文的子類實作,并在政策上下文子類執行個體化時,調用該方法完成具體初始化的工作。
/**
* Flea抽象政策上下文,封裝了公共的政策執行邏輯,
* 其中Flea政策Map由其子類進行初始化,鍵為政策名,
* 值為具體的Flea政策執行個體。
*
* @param <T> Flea政策執行結果對應的類型
* @param <P> Flea政策上下文參數
* @author huazie
* @version 1.1.0
* @since 1.1.0
*/
public abstract class FleaStrategyContext<T, P> implements IFleaStrategyContext<T, P> {
private Map<String, IFleaStrategy<T, P>> fleaStrategyMap; // Flea政策Map
private P contextParam; // Flea政策上下文參數
/**
* 初始化政策上下文
*
* @since 1.1.0
*/
public FleaStrategyContext() {
fleaStrategyMap = init();
}
/**
* 初始化政策上下文
*
* @param contextParam Flea政策上下文參數
* @since 1.1.0
*/
public FleaStrategyContext(P contextParam) {
this();
this.contextParam = contextParam;
}
/**
* 初始化Flea政策Map
*
* @return Flea政策Map
* @since 1.1.0
*/
protected abstract Map<String, IFleaStrategy<T, P>> init();
@Override
public T invoke(String strategy) throws FleaStrategyException {
if (ObjectUtils.isEmpty(fleaStrategyMap)) {
throw new FleaStrategyException("The Strategy Map is not initialized!");
}
IFleaStrategy<T, P> fleaStrategy = fleaStrategyMap.get(strategy);
if (ObjectUtils.isEmpty(fleaStrategy)) {
throw new FleaStrategyNotFoundException("The Strategy [name =\"" + strategy + "\"] is not found!");
}
return fleaStrategy.execute(contextParam);
}
@Override
public void setContext(P contextParam) {
this.contextParam = contextParam;
}
@Override
public P getContext() {
return contextParam;
}
}
3.7 定義動物叫喊聲政策上下文類 — AnimalVoiceContext
動物叫喊聲政策上下文,繼承 Flea 抽象政策上下文,實作 init 方法,用于初始化 Flea 政策實作 Map,其中 key 為 政策名,value 為 具體的動物叫喊聲政策實作類;Collections.unmodifiableMap 用于傳回一個 隻讀 的 Map。
/**
* 動物叫喊聲政策上下文
*
* @author huazie
* @version 1.1.0
* @since 1.1.0
*/
public class AnimalVoiceContext extends FleaStrategyContext<String, String> {
public AnimalVoiceContext() {
}
public AnimalVoiceContext(String contextParam) {
super(contextParam);
}
@Override
protected Map<String, IFleaStrategy<String, String>> init() {
Map<String, IFleaStrategy<String, String>> fleaStrategyMap = new HashMap<>();
fleaStrategyMap.put("dog", new DogVoiceStrategy());
fleaStrategyMap.put("cat", new CatVoiceStrategy());
fleaStrategyMap.put("duck", new DuckVoiceStrategy());
return Collections.unmodifiableMap(fleaStrategyMap);
}
}
3.8 定義Flea政策門面 — FleaStrategyFacade
/**
* Flea政策門面,定義政策調用的統一入口。
*
* @author huazie
* @version 1.1.0
* @since 1.1.0
*/
public class FleaStrategyFacade {
private FleaStrategyFacade() {
}
/**
* 政策門面調用方法
*
* @param strategy 政策名
* @param fleaStrategyContext 政策上下文
* @param <T> Flea政策執行結果對應的類型
* @param <P> Flea政策上下文參數
* @return Flea政策執行結果對應的類型
* @throws FleaStrategyException Flea政策異常
* @since 1.1.0
*/
public static <T, P> T invoke(String strategy, IFleaStrategyContext<T, P> fleaStrategyContext) throws FleaStrategyException {
return fleaStrategyContext.invoke(strategy);
}
}
4. 測試
單元自測類可檢視 FleaStrategyTest。
/**
* @author huazie
* @version 1.1.0
* @since 1.1.0
*/
public class FleaStrategyTest {
private static final FleaLogger LOGGER = FleaLoggerProxy.getProxyInstance(FleaStrategyTest.class);
@Test
public void testStrategy() {
AnimalVoiceContext context = new AnimalVoiceContext("旺财");
LOGGER.debug(FleaStrategyFacade.invoke("dog", context));
context.setContext("Tom");
LOGGER.debug(FleaStrategyFacade.invoke("cat", context));
context.setContext("Donald");
LOGGER.debug(FleaStrategyFacade.invoke("duck", context));
}
}
單元測試類運作結果如下: