通过Spring实现策略模式
当程序中使用太多的if/else/switch来处理不同类型的业务时,会变得极难维护,通过策略模式可以更容易的实现业务扩展和维护。
标准策略模式介绍
比如说对象的某个行为,在不同场景中有不同的实现方式,这样就可以将这些实现方式定义为一组策略,每个实现类对应一个策略,在不同的场景就使用不同的实现类,从而实现自由切换策略。
策略模式结构图如下:
模式概述:
策略模式需要定义一个策略接口,不同的策略都去实现策略接口,在需要调用过程中通过持有该策略接口,然后根据不同的场景去使用不同的实现类。
策略模式的优点:
- 消除繁琐的 if、else判断逻辑;
- 代码结构良好,便于阅读;
- 符合开闭原则,扩展性好、便于维护;
策略模式的缺点:
- 策略如果很多的话,会造成策略类臃肿;
- 其他人使用时必须了解所有的策略类及其用途;
spring实现策略模式
举个例子,例如厂家根据订单生产面条,有兰州拉面,刀削面,重庆小面,然后定义一个生产面条的接口,每种面条的生产方法都去实现这个接口,具体实现方式如下:
1、定义策略接口
定义一个策略接口,所有生产面条的接口。
策略接口:
/**
* 生产面条接口
*/
public interface INoodles {
/**
* 生产面条
* @param order
* @return
*/
Result produce(Order order);
}
订单信息类:
/**
* 订单信息
*/
@Data
public class Order {
/**
* 面条类型
*/
private String noodlesType;
}
返回结果类:
/**
* 返回结果
*/
@Data
@AllArgsConstructor
public class Result {
/**
* 生产结果
*/
private String result;
}
2、定义各种策略
定义各种生产策略,兰州拉面、刀削面、重庆小面等面条实现类都实现这个接口。
兰州拉面实现:
/**
* 生产兰州拉面
*/
@Service("LZNoodles")
public class LZNoodles implements INoodles {
@Override
public Result produce(Order order) {
return new Result("兰州拉面制作完成");
}
}
刀削面实现:
/**
* 生产刀削面
*/
@Service("DXNoodles")
public class DXNoodles implements INoodles {
@Override
public Result create(Order order) {
return new Result("刀削面制作完成");
}
}
重庆小面实现:
/**
* 生产重庆小面
*/
@Service("CQNoodles")
public class CQNoodles implements INoodles {
@Override
public Result create(Order order) {
return new Result("重庆小面制作完成");
}
}
各个面条的实现类通过 @Service 注解生成 Bean 并放入 Spring 容器中,在使用策略的时候就不用 new 对象了。
3、使用策略
标准策略模式使用了枚举、HashMap 的方式来根据策略名称映射策略实现类 ,但是使用了 Spring 框架可以省略这个过程,使用 Bean 名称就能直接找到对应的策略实现类了。
参考示例代码如下:
/**
* 生产面条服务
*/
@RestController
public class NoodlesService {
@Autowired
private ApplicationContext applicationContext;
/**
* 生产面条接口
* @param noodlesType
* @return
*/
@RequestMapping("/noodles")
public Result produce(@RequestParam("noodlesType") String noodlesType) {
Order order = new Order();
order.setNoodlesType(noodlesType);
// 根据面条类型获取对应的策略
INoodles noodles = applicationContext.getBean(order.getNoodlesType(), INoodles.class);
// 开始生产面条
Result result = noodles.produce(order);
return result;
}
}
在参数中传入实现类在spring容器中的名称,通过Spring提供的ApplicationContext接口可以直接获取注入到spring容器中的对象,然后进行后续的处理即可。