需求: 这里虚拟一个业务需求,让大家容易理解。假设有一个订单系统,里面的一个功能是根据订单的不同类型作出不同的处理。
1. 常规代码实现
1.1 实体类
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 接口类
import qinfeng.zheng.strategy.dto.OrderDTO;
public interface IOrderService {
/**
* 根据订单类型做出相应的处理
*
* @param orderDTO
* @return
*/
String handle(OrderDTO orderDTO);
}
1.3 接口实现
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 结论
不用说, 这代码 很low.
2. 使用策略模式实现此功能
策略模式的关键就是一个抽象处理类,配上一个持有这个抽象处理类实例的context. 下面是代码的具体的实现
2.1 抽象类
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那些事儿”
来源:https://www.cnblogs.com/z-qinfeng/p/12210665.html