目录
前情提要
策略模式
什么是策略模式
本业务场景中的几种策略
策略类2
工厂模式
什么是工厂模式
本业务场景中的工厂类
工厂与策略类能结合的关键 -->策略枚举类
SpringUtils类:(从spring中获取实例的工具类)
最终调用类
最后总结
项目需要在后台管理动态切换查询机票或者火车票的三方服务供应商,每一个供应商就代表了不同的一套策略(不过流程是大致相似的 查询-下单或者改签 -出票).
策略模式是一种比较简单的,也叫作政策模式.其定义如下:定义一组算法,将每个算法都封装起来,并且使它们之间可以互相转换.它使用的就是面向对象的继承和多态机制.
--摘自 设计模式之禅
首先是策略抽象接口类
/**
* @Description 策略类接口在此封装了四个策略方法 由不同的服务商实现类去实现
* 具体的服务商实例只能通过 {@link ****.ProvideStrategyFactory} 实例化
* @author liang
*/
public interface IProvideStrategy {
/**
* 查询票务信息
* @param param 查询票务信息参数类
* @return 票务信息列表
*/
ResultVO queryTicketList(QueryTicketParam param);
/**
* 订一张票 进行下单逻辑处理
* @return 下单是否成功(也有可能是等待中)
*/
ResultVO bookOneTicket();
/**
* 改签一张票 进行改签逻辑处理
* @return 改签是否成功(也有可能是等待中)
*/
ResultVO changeTicket();
/**
* 出票方法(这个有可能是放入到回调里面 此处只是留一处口子)
* @return 出票是否成功
*/
ResultVO issueOneTicket();
}
其次是具体的策略类 (请注意策略类都实现了刚才上面的策略抽象接口类 并且用@Component注解 交给spring管理方便后面的工厂类在spring中获取动态代理的实例)
策略类1
/**
* @author liang
* @date 2021年12月13日 14:48
*/
@Component
public class CasCcFlightStrategy implements IProvideStrategy {
@Resource
private CasCcHttpClient casCcHttpClient;
@Override
public ResultVO queryTicketList(QueryTicketParam param) {
return new ResultVO(ResultEnum.SUCCESS,"查询策略1成功");
}
@Override
public ResultVO bookOneTicket() {
return null;
}
@Override
public ResultVO changeTicket() {
return null;
}
@Override
public ResultVO issueOneTicket() {
return null;
}
}
/**
* @author liang
* @date 2021年12月13日 14:50
*/
@Component
public class SpeedFlightStrategy implements IProvideStrategy {
@Resource
private SpeedHttpClient speedHttpClient;
@Override
public ResultVO queryTicketList(QueryTicketParam param) {
return new ResultVO(ResultEnum.SUCCESS,"策略类2查询成功");
}
@Override
public ResultVO bookOneTicket() {
return null;
}
@Override
public ResultVO changeTicket() {
return null;
}
@Override
public ResultVO issueOneTicket() {
return null;
}
}
定义一个用于创建对象的接口,让子类决定实例化那一个类.工厂方法使一个类的实例化延迟到其子类.
--摘自 设计模式之禅
注意 @Component 注解把此工厂类交给spring管理
重载方法可以决定你具体获取的策略类示例是由库里的存储关系决定 还是由前台传参直接决定
/**
* @Description 实例工厂 通过此工厂实例化具体的服务商实现类
* @author liang
* @date 2021年12月13日 14:54
*/
@Component
public class ProvideStrategyFactory {
@Resource
private VipProvidersMapper providersMapper;
/**
* @author liang
* @date 2021/12/15 15:47
* @return 具体的服务商实例
*/
public IProvideStrategy getProvideStrategy(Integer cId, Integer type){
List strategyCode = providersMapper.selectByConferenceIdAndType(cId,type);
if (CommonUtils.isEmpty(strategyCode) || strategyCode.size() > 1){
throw new ServiceException(ResultEnum.SYS_OPERATE_FAIL.getCode(),"服务商配置错误");
}
Class clazz = ProvideFactoryEnum.getFactory(strategyCode.get(0));
return SpringUtils.getBean(clazz);
}
/**
* 通过传参判断枚举的策略类型
* @author liang
* @date 2021/12/23 11:21
* @param factoryEnum 前台传参的策略枚举类型
* @return 具体的服务商实例
*/
public IProvideStrategy getProvideStrategy(ProvideFactoryEnum factoryEnum){
Class clazz = ProvideFactoryEnum.getFactory(factoryEnum.name());
return SpringUtils.getBean(clazz);
}
}
/**
* 给策略工厂提供枚举类型指定要生成的工厂类
* @author liang
*/
public enum ProvideFactoryEnum {
/**
* 这里是服务商的名称和实现类的枚举映射
*/
speedFlight(SpeedFlightStrategy.class),
casCcFlight(CasCcFlightStrategy.class),
speedTrain(SpeedTrainStrategy.class);
private final Class clazz;
ProvideFactoryEnum(Class clazz) {
this.clazz = clazz;
}
public static Class getFactory(String name){
return ProvideFactoryEnum.valueOf(name).clazz;
}
}
/**
* spring工具类 方便在非spring管理环境中获取bean
* @author liang
*/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor
{
/** Spring应用上下文环境 */
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(@NotNull ConfigurableListableBeanFactory beanFactory) throws BeansException
{
SpringUtils.beanFactory = beanFactory;
}
/**
* 获取对象
* @param name 注册的类的名字
* @return Object 一个以所给名字注册的bean的实例
*/
@SuppressWarnings("unchecked")
public static T getBean(String name) throws BeansException
{
return (T) beanFactory.getBean(name);
}
/**
* 获取类型为requiredType的对象
*/
public static T getBean(Class clz) throws BeansException
{
return beanFactory.getBean(clz);
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
* @return boolean
*/
public static boolean containsBean(String name)
{
return beanFactory.containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*
* @return boolean
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.isSingleton(name);
}
/**
* @return Class 注册对象的类型
*/
public static Class> getType(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getAliases(name);
}
/**
* 获取aop代理对象
*/
@SuppressWarnings("unchecked")
public static T getAopProxy(T invoker)
{
return (T) AopContext.currentProxy();
}
}
/**
* @author liang
* @date 2021年12月14日 14:09
*/
@Service
public class TripServiceProvideServiceImpl implements TripServiceProvideService {
@Resource
private ProvideStrategyFactory strategyFactory;
@Override
public ResultVO queryTicket(QueryTicketParam param) {
IProvideStrategy provideStrategy = strategyFactory.getProvideStrategy(param.getcId(),param.getType());
return provideStrategy.queryTicketList(param);
}
}
通过业务逻辑分析 如果需要通过多个第三方完成同样的事(大体上的流程相同,比如支付业务,动态切换服务商等等)就可以采用此策略工厂的设计模式 首先抽象出来策略接口 定义一系列你需要完成的接口 其次根据业务建立不同的策略实现类 实现自己的独立逻辑 最后通过service层就可以调用工厂类从枚举类中拿到真正的策略实例 做到策略的实时动态切换.
本文是真正把策略工厂的设计模式与spring结合在一起的 不是好多博客那种纸上谈兵,如果你有更好的办法欢迎评论区留言