需求: 这里虚拟一个业务需求,让你们容易理解。假设有一个订单系统,里面的一个功能是根据订单的不一样类型做出不一样的处理。java
1. 常规代码实现 web
1.1 实体类spring
import lombok.Data; import java.math.BigDecimal; @Data public class OrderDTO { private String code; private BigDecimal price; /** * 订单类型 * 1: 普通订单 * 2: 团购订单 * 3: 促销订单 */ private String type; }
1.2 接口类app
import qinfeng.zheng.strategy.dto.OrderDTO; public interface IOrderService { /** * 根据订单类型作出相应的处理 * * @param orderDTO * @return */ String handle(OrderDTO orderDTO); }
1.3 接口实现 ide
import org.springframework.stereotype.Service; import qinfeng.zheng.strategy.dto.OrderDTO; import qinfeng.zheng.strategy.service.IOrderService; @Service public class V1OrderServiceImpl implements IOrderService { @Override public String handle(OrderDTO orderDTO) { String type = orderDTO.getType(); if (type.equals("1")) { return "处理普通订单成功"; } if (type.equals("2")) { return "处理团购订单成功"; } if (type.equals("3")) { return "处理促销订单成功"; } return "订单类型不存在"; } }
1.4 结论post
不用说, 这代码 很low. 测试
2. 使用策略模式实现此功能this
策略模式的关键就是一个抽象处理类,配上一个持有这个抽象处理类实例的context. 下面是代码的具体的实现 spa
2.1 抽象类3d
import qinfeng.zheng.strategy.dto.OrderDTO; public abstract class AbsHandler { abstract public String handle(OrderDTO orderDTO); }
2.2 具体实现类
import org.springframework.stereotype.Component; import qinfeng.zheng.strategy.anno.HandlerType; import qinfeng.zheng.strategy.dto.OrderDTO; @Component @HandlerType("1") public class NormalHandler extends AbsHandler { @Override public String handle(OrderDTO orderDTO) { return "处理普通订单"; } }
import org.springframework.stereotype.Component; import qinfeng.zheng.strategy.anno.HandlerType; import qinfeng.zheng.strategy.dto.OrderDTO; @Component @HandlerType("2") public class GroupHandler extends AbsHandler { @Override public String handle(OrderDTO orderDTO) { return "处理团购订单"; } }
import org.springframework.stereotype.Component; import qinfeng.zheng.strategy.anno.HandlerType; import qinfeng.zheng.strategy.dto.OrderDTO; @Component @HandlerType("3") public class PromotionHandler extends AbsHandler { @Override public String handle(OrderDTO orderDTO) { return "处理促销订单"; } }
2.3 context类
public class HandlerContext { private Map<String, Class> handlerMap; public HandlerContext(Map<String, Class> handlerMap) { this.handlerMap = handlerMap; } public AbsHandler getInstance(String type) throws Exception { Class aClass = handlerMap.get(type); if (aClass == null) { throw new IllegalArgumentException("not found handler type :" + type); } return (AbsHandler) aClass.newInstance(); } }
2.3 自定义注解类
import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface HandlerType { String value(); }
2.4 自定义BeanFactory后置处理类,将HandlerContext注册到spring容器中
import cn.hutool.core.lang.ClassScanner; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.stereotype.Component; import qinfeng.zheng.strategy.anno.HandlerType; import qinfeng.zheng.strategy.context.HandlerContext; import java.util.HashMap; import java.util.Map; @Component public class HandlerProcessor implements BeanFactoryPostProcessor { private static final String HANDLE_PACKAGE = "qinfeng.zheng.strategy"; /** * 扫描@HandlerType注解,初始化HandlerContext, 并将其注册到spring容器中 * @param beanFactory bean工厂呀...... * @throws BeansException */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { Map<String, Class> handlerMap = new HashMap<>(); ClassScanner.scanPackageByAnnotation(HANDLE_PACKAGE,HandlerType.class).forEach(aClass -> { String value = aClass.getAnnotation(HandlerType.class).value(); handlerMap.put(value, aClass); }); // 初始化HandlerContext HandlerContext handlerContext = new HandlerContext(handlerMap); // 手动将HandlerContext注册到spring容器中 beanFactory.registerSingleton(HandlerContext.class.getName(), handlerContext); } }
2.4 修改IOrderService接口实现
@Service public class V2OrderServiceImpl implements IOrderService { @Autowired private HandlerContext handlerContext; @Transactional @Override public String handle(OrderDTO orderDTO) throws Exception { AbsHandler handler = handlerContext.getInstance(orderDTO.getType()); return handler.handle(orderDTO); } }
2.5 写个controller测试一下
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import qinfeng.zheng.strategy.dto.OrderDTO; import qinfeng.zheng.strategy.service.IOrderService; @RestController public class OrderController { /** * @Autowired自定根据 v2OrderServiceImpl 名称 适配 V2OrderServiceImpl这个实现类 */ @Autowired private IOrderService v2OrderServiceImpl; @GetMapping("/handle") public String handler(OrderDTO orderDTO) throws Exception { return v2OrderServiceImpl.handle(orderDTO); } }
好, 代码写完了,使用策略模式以后,代码的扩展性确实加强,若订单类型发生改变,只需添加AbsHandler的实现类便可,其它都不须要变。
可是,我以为这代码并很差呀, 这样操做,实现策略模式的代码太多了。 其二,我使用了 aClass.newInstance()反射方式建立一个具体的Handler对象,这儿并无使用spring的代理功能,因此若是在AbsHandler#handle方法上添加事务,是不会生效的,只能在V2OrderServiceImpl#handle方法添加事务。
不过这个示例也让我真实体验了一把 BeanFactoryPostProcessor 这个接口的功能, 之后若是有须要手动注册bean的场景,能够考虑使用这个接口,可是这个接口的主要功能并不注册bean, 而是修改管理bean工厂内全部的beandefinition(未实例化)数据,而且为所欲为的修改属性。
此外,ClassScanner这个类使用hutool类库。
以上示例代码大多来自“java那些事儿”