策略模式可以说是应用十分广泛的一种设计模式。关于它的定义这里就不赘述了,简单理解它的思想其实就是switch-case,只不过它是以拓展类的方式来增加case的,这样带来的好处是开发者只需要增加类而不修改代码就能应对新增的业务场景。
在项目中,service天然就为我们提供了使用策略模式的条件。我们可以对一个接口写多个实现类,如下图:
public interface StrategyService { void print(); String type();}
@Service("aStrategy")public class AStrategyServiceImpl implements StrategyService { @Override public void print() { System.out.println("AService"); } @Override public String type() { return "A"; }}
@Service("bStrategy")public class BStrategyServiceImpl implements StrategyService { @Override public void print() { System.out.println("BService"); } @Override public String type() { return "B"; }}
@Service("cStrategy")public class CStrategyServiceImpl implements StrategyService { @Override public void print() { System.out.println("CService"); } @Override public String type() { return "C"; }}
只需要为每个实现类指定beanName,再根据beanName从applicationContext中获取对应的实例即可。
public class StrategyUtils{ public void doSomting(String beanName){ Object temp = applicationContext.getBean(beanName); if (temp instanceof StrategyService){ StrategyService cService = (StrategyService)temp; cService.print(); }else { throw new RuntimeException("不支持的beanName"); } } }
但是这种方式需要try catch 处理 NoSuchBeanDefinitionException:No bean named 'xxx' available异常,如果你不喜欢这种写法,可以继续看下面。
考虑使用HashMap来存储StrategyService的所有实例,利用@PostConstruct注解初始化将StrategyService的实例都put到map中,key值设置为每个bean的type(),相当于beanName,这样通过map获取到的实例必然是StrategyService类型。
@Componentpublic class StrategyUtils { private List strategyServices; private static HashMap map = new HashMap<>(); private StrategyProperties strategyProperties; @Autowired public void setStrategyServices(List strategyServices) { this.strategyServices = strategyServices; } @Autowired public void setStrategyProperties(StrategyProperties strategyProperties) { this.strategyProperties = strategyProperties; } public StrategyService getService(String type) { if (!StringUtils.hasText(type)) { type = strategyProperties.getDefaultType(); } if (strategyProperties.getDisabledTypes().contains(type)) { throw new RuntimeException(type + "已被禁止使用"); } if (map.get(type) == null){ throw new RuntimeException(type + "不支持"); } return map.get(type); } public void doSomething(String type){ this.getService(type).print(); } @PostConstruct public void init() { if (strategyServices != null) { strategyServices.forEach(service -> map.put(service.type(), service)); } }}
我们还可以通过引入配置类,让getService()变得更加灵活。
@ConfigurationProperties(prefix = "strategy.properties")public class StrategyProperties { //默认type private String defaultType = "A"; //禁用的type private List disabledTypes = new ArrayList<>();......}
strategy: properties: defaultType: B disabledTypes: - C - D
当然,在实际使用中,我们可能倾向直接获取service进行操作。
@GetMapping("/test")public void testAlias(@RequestParam String type) { //strategyUtils.doSomething(type);StrategyService service = strategyUtils.getService(type);......}
小伙伴们,在不确定项目业务场景是否会拓展的情况下,考虑使用策略模式取代if-else if 吧!
留言与评论(共有 0 条评论) “” |