应用场景
策略模式侧重点是一个行为的多个算法的实现,可互换算法。
简单来说,不同类型走不同的算法,可以避免冗长的if else,实现横向扩展。
比如电商网站下单,不同订单有不同的算法,但它们有一个共同点:对订单进行计算处理。属于同一个行为,但是订单类型不同。
实现方式
可能我们首先想到的是使用if else,写出下面的方法:
if (orderType.equals("computer")) {
//电脑订单的算法
} else if (orderType.equals("food")) {
//食物订单的算法
} else {
//其他类型订单的算法
}
这种写法,如果后续新增很多订单算法,那么必须修改这里的代码!
根据设计模式原则,我们需要隔离变化的,让其他部分不受它的影响,因此我们对此进行改进,这时就需要用到面向接口编程!
类图
- 定义一个接口类OrderHandler
- 实现OrderHandler的有两个具体的订单计算类
- OrderController是使用者,一定会持有OrderHandler接口变量
代码实现
以下代码有些和类图命名方式不一样,不过原理都是相同的。
OderHandler接口类:
public interface OrderHandler {
boolean support(String orderType);
void handler();
}
Computer订单实现类:
@Component
public class ComputerOrderHandlerImpl implements OrderHandler {
public static String ORDER_TYPE = "computer";
@Override
public boolean support(String orderType) {
return orderType.equals(ComputerOrderHandlerImpl.ORDER_TYPE);
}
@Override
public void handler() {
System.out.println("策略模式:调用ComputerOrderHandler进行处理");
}
}
Food订单实现类
@Component
public class FoodOrderHandlerImpl implements OrderHandler {
public static String ORDER_TYPE = "food";
@Override
public boolean support(String orderType) {
return orderType.equals(FoodOrderHandlerImpl.ORDER_TYPE);
}
@Override
public void handler() {
System.out.println("策略模式:调用FoodOrderHandler进行处理");
}
}
外部使用类:
@Controller
@RequestMapping("/strategy")
public class StrategyTestController {
@RequestMapping("/test.json")
@ResponseBody
public String test() {
String orderType = "computer";
//获取所有类型为OrderHandler.class的类
Map<String, OrderHandler> beansMap = SpringContextUtil.getApplicationContext().getBeansOfType(OrderHandler.class);
//处理
for (Map.Entry<String, OrderHandler> entry : beansMap.entrySet()) {
if (entry.getValue().support(orderType)) {
//调用对应的订单类型处理类
entry.getValue().handler();
}
}
return "strategy success";
}
}
SpringContextUtil工具类:
@Component
public class SpringContextUtil implements ApplicationContextAware{
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}