利用策略模式优化过多if else代码
1.应用场景
现在需要完成这样一项业务,客户在前端输入算法名,后台就调用对应算法来进行模拟实验。假设不使用策略模式,那么我就需要以下代码实现该业务:
@Autowired
private DqnAlgorithm dqn;
@Autowired
private GreedyAlgorithm greedy;
@GetMapping("/simu/{alName}")
public Result getResult(@PathVariable String alName) {
String ret = null;
if (alName.equals("DqnAlgorithm")) {
// 调用dqn的算法
ret = dqn.compute();
}else if (alName.equals("DqnAlgorithm")) {
ret = greedy.compute()
}
return ret;
}
如果我以后实现了更多算法,那么就需要注入更多算法bean,增加更多if else,非常不优雅。
于是决定使用策略模式来解决这个问题。
2.策略模式
首先将算法类抽象出一个接口,接口中有方法compute,实现类都实现这个接口,并且都注册成为Service交给Spring容器管理。因为前端输入算法名alName我们就需要找到正确的实现类Bean并注入,所以需要找出算法接口的所有实现类(AlgorithmServiceLocator提供),根据类名提供其实例(AlgorithmService提供),最终调用方法。
Monodraw第一次画图:
┌──────────────────register────┐
│ │
│ │
┌─────────────────┐ │
│ IAlgorithm │ │
└───────▲─▲───────┘ │
│ │ │
┌────────┘ └─────────┐ │
│ │ │
│ │ │
┌──────────────────┐ ┌──────────────────┐ │
│ GreedyAlgorithm │ │ DqnAlgorithm │ ▼
└──────────────────┘ └──────────────────┘ .─────.
,' `.
┌──────map───────────┐ ; :
│ │ ; :
▼ │ ; :
┌───────────────────────────────┐ │ │ Spring Bean │
│ AlgorithmServiceLocator │ └───│ container │
└───────────────────────────────┘ : ;
get : ;
IAlgorithm : ;
│ ╲ ╱
▼ `. ,'
┌──────────────────────────────┐ `───'
│ AlgorithmService │
└──────────────────────────────┘
3.文件与代码
接口IAlgorithm
public interface IAlgorithm {
String compute();
}
两个算法实现类
@Service("DqnAlgorithm")
public class DqnAlgorithm implements IAlgorithm{
@Override
public String compute() {
return "Deep Q learning...";
}
}
@Service("GreedyAlgorithm")
public class GreedyAlgorithm implements IAlgorithm{
@Override
public String compute() {
return "贪心算法...";
}
}
获取接口所有实现类的工具类AlgorithmServiceLocator
@Component
public class AlgorithmServiceLocator implements ApplicationContextAware {
private Map<String, IAlgorithm> map;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
map = applicationContext.getBeansOfType(IAlgorithm.class);
}
public Map<String, IAlgorithm> getMap() {
return map;
}
}
业务类:根据算法名获取对应实现类,并调用方法取得结果
@Service
public class AlgorithmService {
@Autowired
private AlgorithmServiceLocator algorithmLocator;
public IAlgorithm getInstance(String algorithm) {
IAlgorithm al = null;
try {
Map<String, IAlgorithm> map = algorithmLocator.getMap();
System.out.println(map);
al = map.get(algorithm);
}catch (Exception e) {
e.printStackTrace();
}
return al;
}
public String getRet(String algorithm) {
IAlgorithm al = getInstance(algorithm);
if (al == null) {
throw new RuntimeException("无法获取算法!");
}
String ret = al.compute();
return ret;
}
}
controller
@RestController
public class SimulationController {
@Autowired
private AlgorithmService algorithmService;
@GetMapping("/simu/{alName}")
public String getResult(@PathVariable String alName) {
return algorithmService.getRet(alName);
}
}
测试图1
测试图2
4. 总结
策略模式需要反射的配合,有时间要学习一下。