利用策略模式优化过多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.策略模式

image1
首先将算法类抽象出一个接口,接口中有方法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
image
测试图2
image

4. 总结

策略模式需要反射的配合,有时间要学习一下。

参考博客文章

crossoverjie
绝圣弃智-零-csdn

posted @ 2022-03-06 21:33  cee_nil  阅读(167)  评论(0编辑  收藏  举报