设计模式之策略模式(if..else肿瘤代码)
2020-06-02 05:50
323 查看
你是否有过类似如下的业务代码,每种业务类型都有不同的处理数据,但是要返回的结果功能是一样的:
/** * 根据课程名字查询价格 * @param courseName 课程名字 * @return 课程价格 */ public BigDecimal findPriceByName(String courseName){ if (StringUtils.isNotBlank(courseName)){ //如果前端参数为English if (CourseType.ENGLISH.getCourseName().equals(courseName)){ return this.englishService.getEnglishPrice(courseName); } //如果前端参数为Chinese if (CourseType.CHINESE.getCourseName().equals(courseName)){ return this.chineseService.getChinesePrice(courseName); } //如果前端参数为Math if (CourseType.MATH.getCourseName().equals(courseName)){ return this.mathService.getMathPrice(courseName); } //.......... } }
那么如果随着公司的业务线不断增大,或许以后增加至几十种业务产品,当然,我所举得代码例子过于简单,但是不碍于我表达这类似的业务问题。随着产品业务增加,是不是每次都要来修改这又臭又长的if…else…,像一个肿瘤一样。这时候其实根据业务需求改善一下,比如采用
策略模式来重构一下,结构变得清晰很多。我就以最简单的一个例子说起,根据课程的名字查询课程的价格,每一种产品的查询方式或者需要做数据处理不一致,但是功能都是查询价格,不妨将这公共的功能抽取出来,借助Spring的IOC容器因地制宜地解决此问题。
1.创建策略接口
/** * 课程策略接口 */ public interface CourseStrategy { /** * 根据课程名字查询价格 * @param courseName 课程名字 * @return 课程价格 */ BigDecimal findPriceByName(String courseName); }
2.每种产品服务类实现该接口
- 不同service实现接口并根据不同的产品需求重写策略方法
@Service public class ChineseService implements CourseStrategy { @Override public BigDecimal findPrice() { return new BigDecimal(300);//业务查询逻辑,我就举个简单例子了 } }
@Service public class MathService implements CourseStrategy { @Override public BigDecimal findPrice() { return new BigDecimal(200);//业务查询逻辑,我就举个简单例子了 } }
@Service public class EnglishService implements CourseStrategy { @Override public BigDecimal findPrice() { return new BigDecimal(100);//业务查询逻辑,我就举个简单例子了 } }
3.枚举类(下文有其它方案)
public enum CourseType { ENGLISH("English","englishService"), CHINESE("Chinese","chineseService"), MATH("Math","mathService"); private String courseName; private String serviceName; CourseType(String courseName,String serviceName){ this.courseName = courseName; this.serviceName = serviceName; } public static String getServiceBeanName(String courseName) { if (StringUtils.isNotBlank(courseName)) { for (CourseType course : CourseType.values()) { if (courseName.equals(course.getCourseName())) { return course.getServiceName(); } } } return null; } public String getCourseName(){ return courseName;} public String getServiceName(){ return serviceName;} }
4.服务调用类
通过IOC容器进行不同的实现不同的处理逻辑
/** * 课程服务 */ @Service public class CourseManager implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /** * 根据课程名字查询价格 * @param courseName 课程名字 * @return 课程价格 */ public BigDecimal findPriceByName(String courseName){ if (StringUtils.isNotBlank(courseName)){ //从容器中根据serviceName取出对应的实现类 CourseStrategy strategy = (CourseStrategy)applicationContext.getBean(CourseType.getServiceBeanName(courseName)); BigDecimal price = strategy.findPrice(); System.out.println(courseName+"产品一共:"+price+"元"); return price; } return null; } }
5.测试一下
@Test public void StrategyTest() throws Exception { courseManager.findPriceByName("English"); courseManager.findPriceByName("Chinese"); courseManager.findPriceByName("Math"); }
English产品一共:100元 Chinese产品一共:300元 Math产品一共:200元
第三步也算是有一定耦合,可以继续改造:
- 可以写一个注解,不同的产品service加上此策略注解,然后服务调用类通过反射方式获取service类名,然后通过IOC容器调用。
- 可以在服务调用类中实例化一个Map,不同产品service实例化后注册进Map中,我们演示一下此方法。
@Service @DependsOn("courseManager") public class ChineseService implements CourseStrategy, InitializingBean { @Override public void afterPropertiesSet() throws Exception { CourseManager.STRATEGY_BEANS.put("Chinese", this); } @Override public BigDecimal findPrice() { return new BigDecimal(300);//业务查询逻辑,我就举个简单例子了 } }
@Service @DependsOn("courseManager") public class MathService implements CourseStrategy, InitializingBean { @Override public void afterPropertiesSet() throws Exception { CourseManager.STRATEGY_BEANS.put("Math", this); } @Override public BigDecimal findPrice() { return new BigDecimal(200);//业务查询逻辑,我就举个简单例子了 } }
@Service @DependsOn("courseManager") public class EnglishService implements CourseStrategy, InitializingBean { @Override public void afterPropertiesSet() throws Exception { CourseManager.STRATEGY_BEANS.put("English", this); } @Override public BigDecimal findPrice() { return new BigDecimal(100);//业务查询逻辑,我就举个简单例子了 } }
然后是服务调用类:
/** * 课程服务 */ @Service public class CourseManager{ public static final Map<String,Object> STRATEGY_BEANS = new ConcurrentHashMap<>(); /** * 根据课程名字查询价格 * @param courseName 课程名字 * @return 课程价格 */ public BigDecimal findPriceByName(String courseName){ if (StringUtils.isNotBlank(courseName)){ //从Map中对应的实现类 CourseStrategy strategy = (CourseStrategy)STRATEGY_BEANS.get(courseName); if (strategy != null){ BigDecimal price = strategy.findPrice(); System.out.println(courseName+"产品一共:"+price+"元"); return price; } } return null; } }
测试结果:
English产品一共:100元 Chinese产品一共:300元 Math产品一共:200元
值得注意的是
InitializingBean这个接口的
afterPropertiesSet方法,初始化Bean就会调用这个方法,这里直接将bean放入Map中,引用地址就是IOC中的Bean地址,这样修改后也达到了策略的方式。相比较于最初的服务,现在不管新增多少不同产品的实现,只要实现策略接口重写其方法,将其Bean放入Map中即可,也符合了服务控制类的开闭原则。
@DependsOn("")此注解的目的是让spring容器按照顺序加载Bean,此注解具体细节可自行百度。
相关文章推荐
- 策略模式优化过多的if else 代码
- 利用策略模式优化过多 if else 代码
- 设计模式-策略模式Strategy以及消灭if else
- 利用策略模式和工厂模式优化代码中过多的if-else
- Java利用策略模式优化过多if else代码
- 设计模式——行为型模式之借助策略模式(Strategy Pattern)减少使用不必要的if-else if -else和switch-case(三)
- Android设计模式 -- 巧用策略模式告别过多的 if...else...
- 大量if else 或者switch case可以采用的设计模式-----状态模式
- 从if else 到设计模式的转变
- 设计模式--策略模式示例代码
- 用设计模式来代替臃肿的ifelse层层判断 .
- 使用策略模式减少if else
- Java中利用设计模式来代替复杂的if...else...语句(三层以上的嵌套循环)
- 策略模式代替大量的if else
- Strategy 设计模式 策略模式 超靠谱原代码讲解
- Java设计模式之策略模式代码示例
- Strategy 设计模式 策略模式 超靠谱原代码讲解
- Delphi 设计模式:《HeadFirst设计模式》Delphi7代码---策略模式之MiniDuckSimulator
- 策略模式:再见if-else
- 给你的if-else穿穿新衣-设计模式体验-Java