1、策略模式簡介
設(shè)計模式的知識可以參考我的設(shè)計模式筆記專欄:設(shè)計模式系列博客
策略模式:定義一系列算法蚕键,然后將每一個算法封裝起來宪巨,并將它們可以互相替換捅伤。也就是將一系列算法封裝到一系列策略類里面轴术。策略模式是一種對象行為型模式难衰。策略模式符合“開閉原則“
Strategy Pattern: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
策略模式包括如下角色:
Context :環(huán)境類
Strategy:抽象策略類
-
ConcreteStrategy:具體策略類
策略模式和狀態(tài)模式常用于處理業(yè)務(wù)比較繁雜的場景,因為業(yè)務(wù)經(jīng)常變更逗栽,有時候隨著業(yè)務(wù)堆積盖袭,會出現(xiàn)大量的if...else,造成代碼可讀性變差彼宠,所以可以使用策略模式和狀態(tài)模式等設(shè)計模式進行業(yè)務(wù)解耦鳄虱,提高代碼可讀性
2、典型例子實現(xiàn)
業(yè)務(wù)場景:提供一個統(tǒng)一的頁面凭峡,嵌套各個子系統(tǒng)拙已,點擊各個子系統(tǒng)時候,會進行業(yè)務(wù)處理摧冀,然后進行跳轉(zhuǎn)
業(yè)務(wù)聽起來很簡單倍踪,所以就簡單敲下代碼:
public ModelAndView toSysPage(@RequestParam("type")String type, HttpServletRequest request){
String viewName = "login/unifyLogin";
String isCaLogin = request.getParameter(IS_CA_LOGIN);
if (!StringUtils.isEmpty(isCaLogin) && "true".equalsIgnoreCase(isCaLogin)) {
if (SysTypeEnum.SYS_APPR_CONTROL.getType().equals(type) ) {
viewName = "login/yzsCA";
} else if(SysTypeEnum.SYS_APPR_UNION_CONTROL.getType().equals(type) ) {
viewName = "login/ydblCA";
} else if(SysTypeEnum.SYS_APPR_UNIFY_WEB.getType().equals(type) ) {
viewName = "login/jsgcCA";
}
}
if (SysTypeEnum.SYS_APPR_CONTROL.getType().equals(type) && (StringUtils.isEmpty(isCaLogin) || !"true".equals(isCaLogin))) {
viewName = "login/yzsLogin";
} else if(SysTypeEnum.SYS_APPR_UNION_CONTROL.getType().equals(type) && (StringUtils.isEmpty(isCaLogin) || !"true".equals(isCaLogin))) {
viewName = "login/ydblLogin";
} else if(SysTypeEnum.SYS_APPR_UNIFY_WEB.getType().equals(type) && (StringUtils.isEmpty(isCaLogin) || !"true".equals(isCaLogin))) {
viewName = "login/jsgcLogin";
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName(viewName);
return modelAndView;
}
然后,和現(xiàn)場溝通索昂,發(fā)現(xiàn)還要增加系統(tǒng)建车,業(yè)務(wù)也要增加,所以就要增加if...else的數(shù)量椒惨,業(yè)務(wù)一堆積缤至,代碼就變得很雜,不好維護框产,所以用策略模式進行改進
- 定義元注解:
import org.springframework.stereotype.Service;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited //子類可以繼承此注解
public @interface SysType {
String type();
}
- 寫個策略接口
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;
public interface SysHandler {
ModelAndView invokeModelAndView(Map<String,Object> params);
}
- 各個系統(tǒng)都實現(xiàn)接口凄杯,進行不同的業(yè)務(wù)處理,
@SysType(type = "sys1")
表示系統(tǒng)type秉宿,@Component記得加上戒突,才可以加到Spring容器里
@SysType(type = "sys1")
@Component
public class ApprControlSysHandler implements SysHandler{
@Override
public ModelAndView invokeModelAndView(Map<String,Object> params) {
//...
return modelAndView;
}
}
- 在一個@Service類里,將實現(xiàn)SysHandler接口的類都裝載到Spring容器
public static Map<String, SysHandler> sysHandlerMap = new HashMap<String, SysHandler>(16);
@Autowired
ApplicationContext applicationContext;
/**
* 裝載到Spring容器
* @Author nicky
* @Date 2020/06/23 17:47
* @Param [applicationContext]
* @return void
*/
@PostConstruct
public void buildSysHandlerMap() {
Map<String, Object> map = applicationContext
.getBeansWithAnnotation(SysType.class);
for (Map.Entry<String, Object> entry : map.entrySet()) {
Class<SysHandler> sysHandlerClass = (Class<SysHandler>)entry.getValue().getClass() ;
String type = sysHandlerClass.getAnnotation(SysType.class).type();
sysHandlerMap.put(type,applicationContext.getBean(sysHandlerClass));
}
}
- 調(diào)用描睦,進行改造膊存,代碼簡潔很多
public ModelAndView toSysPage(String type, HttpServletRequest request){
Assert.notNull(type, "type can not null");
SysHandler sysHandler = sysHandlerMap.get(type);
Map<String, Object> params = new HashMap<String, Object>(16);
params.put("isCaLogin", isCaLogin);
params = Collections.unmodifiableMap(params);
return modelAndView = sysHandler.invokeModelAndView(params);
}
看了類圖,也很清晰忱叭,這是策略模式的簡單應(yīng)用隔崎,有什么問題歡迎指出