什么是策略模式
指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法
在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护
如我最近写的爬虫小说,行为是爬取小说内容,但是针对不同的网站,实现都不一样
本文利用spring和java的新特性,整理了策略模式的两种实现方式
本文收获
1.java8的lambda
2.spring的aware接口
3.策略模式
实现方式
方式一:
1. 定义接口和实现类,给每个不同的实现类指定 key
/**
* 定义接口
*/
public interface TestProxy {
public String getTestKey();
public void operate(Map<String, String> param) throws IOException;
}
@Component
public class TestProxyImpl implements TestProxy {
@Override
public String getTestKey() {
return "test1";
}
@Override
public int[] operate(int[] arr) {
System.out.println("我是快速排序算法");
return arr;
}
}
@Component
public class Test2ProxyImpl implements TestProxy {
@Override
public String getTestKey() {
return "test2";
}
@Override
public int[] operate(int[] arr) {
System.out.println("我是选择排序算法");
return arr;
}
}
2. 实现 Aware 接口,并通过 map 关联存储 key 和策略对象
/**
* 实现spring的Aware接口
* 通过class获取对象
*/
@Component
public class TestFactory implements ApplicationContextAware {
private Map<String, TestProxy> beanMap;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//获取指定接口的实现类
Map<String, TestProxy> map = applicationContext.getBeansOfType(TestProxy.class);
this.beanMap = new HashMap<>(map.size());
map.forEach((k, v) -> this.beanMap.put(v.getBookEnum().name(), v));
}
/**
* 通过策略key获取具体的对象
*/
public <T extends TestProxy> T getTestProxy(String code) {
return (T)this.beanMap.get(code);
}
}
3. 通过 key 动态选择策略
@GetMapping({"/testStrategy/{key}"})
@ApiOperation(value = "测试接口", notes = "test")
public void testStrategy(@PathVariable("key") String key) throws Exception {
TestProxy testProxy = testFactory.getTestProxy(key);
int[] arr = new int[]{5,1,2,3,4};
int[] result = testProxy.operate(arr);
System.out.println(result);
}
方式二:
1. 定义策略
public interface ITestService {
String method1(Map<String, String> map);
String method2(Map<String, String> map);
String method3(Map<String, String> map);
}
2. 通过 Function 函数存储策略
@Service
public class NewStrategy {
@Autowired
private ITestService iTestService;
private static final Map<String, Function<Map<String, String>, String>> GRANT_TYPE_MAP =new HashMap<>();
/**
* 通过function初始化业务分派逻辑,代替了if-else部分
* key: 策略key
* value: 方法体
*/
@PostConstruct
public void newStrategy(){
GRANT_TYPE_MAP.put("method1",v->iTestService.method1(v));
GRANT_TYPE_MAP.put("method2",v->iTestService.method2(v));
GRANT_TYPE_MAP.put("method3",v->iTestService.method3(v));
}
public static String getResult(String key, Map<String, String> param){
//根据key获取具体的策略
Function<Map<String, String>, String> result = GRANT_TYPE_MAP.get(key);
if(result!=null){
//传入参数执行方法体
return result.apply(param);
}
return null;
}
}
3. 通过 key 动态选择策略
@PostMapping ({"/getResult/{type}"})
@ApiOperation(value = "测试策略活动的新玩法", notes = "test")
@ResponseBody
public String getResult(@RequestBody Map<String, String> param, @PathVariable("type") String type) {
return NewStrategy.getResult(type, param);
}
两者区别
1. 细粒度不同,前者以对象为单位,每一个新的策略都需要定义 key 和实现接口,后者只需关注策略方法即可
2. 技术性不同,前者通过 spring 的 Aware 接口玩法实现,后者通过 java 的 lambda 函数式编程实现
题外话
Aware是spring系列一个比较常用的接口,用它可以实现一些方便的操作
如获取对象,获取当前环境
@Component
public class BeanFactory implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanFactory.context = applicationContext;
}
/**
* 通过class获取对象
*/
public static <T> T getBean(Class<T> className) {
return context.getBean(className);
}
/**
* 获取当前项目环境
*/
public static String getActiveProfile() {
return context.getEnvironment().getActiveProfiles()[0];
}
}
Python 系列:
读取文件 – 使用 python 读取 xls,xlsx,csv,doc,docx,pdf 格式的文件
阅读小工具 – 使用 python 开发无边框窗体阅读小工具
操作xlsx文件 – 使用 openpyxl 技术对 xlsx 的各种操作
前端系列:
扫雷游戏 – JavaScript 仿造 windows 编写 扫雷游戏
前端工具库 xlsx 处理表头合并 – 如何使用 xlsx 技术处理复杂的表头合并
CSS 布局技巧 – 对整体布局的心得体会
NVM Node 多版本控制教程 – Node 版本控制神器 NVM
Spring 系列:
Spring部署 – Spring 的多种 linux 部署方式
Spring实现策略模式 – 通过 Spring 实现多种策略模式