整体思路:通过在策略类上使用自定义注解,定义的orderType不同来区分各种订单,再根据不同的orderType将策略类存储,使用时再根据orderType获取策略类做不同的处理。
代码结构:(案例以京东、淘宝、苏宁订单类型为例)
二、代码 1、自定义策略注解 注解import com.hong.strategy.enums.OrderTypeEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface OrderTypeAnnotation {
OrderTypeEnum orderType();
}
枚举
public enum OrderTypeEnum {
TB(1, "淘宝订单"),
JD(2, "京东订单"),
SN(3, "苏宁订单");
private Integer orderType;
private String desc;
OrderTypeEnum(int orderType, String desc) {
this.orderType = orderType;
this.desc = desc;
}
public static OrderTypeEnum getEnum(Integer orderType) {
OrderTypeEnum[] typeArray = OrderTypeEnum.values();
for (OrderTypeEnum typeEnum : typeArray) {
if (typeEnum.getOrderType().equals(orderType)) {
return typeEnum;
}
}
return null;
}
//此处忽略get和set方法
}
2、策略接口和实现
说明
订单策略-接口OrderStrategy-接口 getUserInfo(获取用户信息) getGoodsInfo(获取商品信息) getDiscount(获取优惠金额) AbstractOrderStrategy-抽象类 实现OrderStrategy接口所有方法 JdOrderStrategy-京东订单策略类 继承AbstractOrderStrategy抽象类 重写getGoodsInfo、getDiscount SnOrderStrategy-苏宁订单策略类 继承AbstractOrderStrategy抽象类 重写getGoodsInfo、getDiscount TbOrderStrategy-淘宝订单策略类 继承AbstractOrderStrategy抽象类 重写getGoodsInfoAbstractOrderStrategy抽象类做通用处理类,其他策略类用来做特殊处理类
例如:获取用户信息是通用的,那么我们不需要在策略类中去实现他;
每个平台的优惠不一样,我们则需要对每个平台做不同的处理,那么,这个就可以在策略类中重写getDiscount方法来实现。
public interface OrderStrategy {
String getUserInfo(String buyer);
String getGoodsInfo(String goodsName);
Double getDiscount();
}
订单策略-抽象类
存放一些通用的基础方法。若不同的实现类有不同的需求,可在实现类中重写该方法,来实现自定义业务逻辑
import com.hong.strategy.strategys.service.OrderStrategy;
public abstract class AbstractOrderStrategy implements OrderStrategy {
@Override
public String getUserInfo(String buyer) {
return buyer;
}
@Override
public String getGoodsInfo(String goodsName) {
return goodsName;
}
@Override
public Double getDiscount() {
return 0.0;
}
}
京东订单-策略类
import com.hong.strategy.enums.OrderTypeEnum;
import com.hong.strategy.strategys.annotation.OrderTypeAnnotation;
import org.springframework.stereotype.Component;
@Component
@OrderTypeAnnotation(orderType = OrderTypeEnum.JD)
public class JdOrderStrategy extends AbstractOrderStrategy {
@Override
public String getGoodsInfo(String goodsName) {
return "【京东】" + goodsName;
}
@Override
public Double getDiscount() {
return 50.0;
}
}
苏宁订单-策略类
import com.hong.strategy.enums.OrderTypeEnum;
import com.hong.strategy.strategys.annotation.OrderTypeAnnotation;
import org.springframework.stereotype.Component;
@Component
@OrderTypeAnnotation(orderType = OrderTypeEnum.SN) //使用注解标明策略类型
public class SnOrderStrategy extends AbstractOrderStrategy {
@Override
public String getGoodsInfo(String goodsName) {
return "【苏宁】" + goodsName;
}
@Override
public Double getDiscount() {
return 100.0;
}
}
淘宝订单-策略类
import com.hong.strategy.enums.OrderTypeEnum;
import com.hong.strategy.strategys.annotation.OrderTypeAnnotation;
import org.springframework.stereotype.Component;
@Component
@OrderTypeAnnotation(orderType = OrderTypeEnum.TB)
public class TbOrderStrategy extends AbstractOrderStrategy {
@Override
public String getGoodsInfo(String goodsName) {
return "【淘宝】" + goodsName;
}
}
3、核心功能实现
import com.hong.strategy.enums.BizResultCode;
import com.hong.strategy.enums.OrderTypeEnum;
import com.hong.strategy.exception.BizException;
import com.hong.strategy.strategys.annotation.OrderTypeAnnotation;
import com.hong.strategy.strategys.service.OrderStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class HandlerOrderContext implements ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(HandlerOrderContext.class);
private static final Object lock = new Object();
private static Map> orderStrategyBeanMap = new HashMap<>();
@Autowired
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
HandlerOrderContext.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static OrderStrategy getInstance(Integer orderType) {
if (null == orderType) {
throw new BizException(BizResultCode.ERR_PARAM.getCode(), "订单类型不能为空");
}
OrderTypeEnum orderTypeEnum = OrderTypeEnum.getEnum(orderType);
if (null == orderTypeEnum) {
throw new BizException(BizResultCode.ERR_PARAM.getCode(), "暂时不支持该订单类型orderType=" + orderType);
}
// 当集合为空时,则初始化
if (orderStrategyBeanMap.size() == 0) {
initStrategy();
}
Class extends OrderStrategy> clazz = orderStrategyBeanMap.get(orderTypeEnum);
if (null == clazz) {
throw new BizException(BizResultCode.ERR_PARAM.getCode(), "未找到订单类型(" + orderTypeEnum + ")的创建订单策略实现类");
}
// 从spring容器中获取bean
return applicationContext.getBean(clazz);
}
private static void initStrategy() {
synchronized (lock) {
// 获取接口下所有实例bean
Map strategyMap = applicationContext.getBeansOfType(OrderStrategy.class);
if (null == strategyMap || strategyMap.size() == 0) {
throw new BizException(BizResultCode.ERR_SYSTEM.getCode(), "代码配置错误:未获取到OrderStrategy的实现类,请检查代码中是否有将实现类bean注册到spring容器");
}
// 加载所有策略类对应的配置
OrderTypeAnnotation annotation;
for (Map.Entry strategy : strategyMap.entrySet()) {
Class strategyClazz = strategy.getValue().getClass();
// 因为策略bean可能是经过动态代理生成的bean实例(可能是多重动态代理后的代理对象),
// 故而bean实例的class可能已经不是原来的class了,所以beanClass.getAnnotation(...)获取不到对应的注解元信息
annotation = (OrderTypeAnnotation) strategyClazz.getAnnotation(OrderTypeAnnotation.class);
if (null == annotation) {
// 当从bean实例的class上获取不到注解元信息时,通过AnnotationUtils工具类递归来获取
annotation = AnnotationUtils.findAnnotation(strategyClazz, OrderTypeAnnotation.class);
if (null == annotation) {
logger.warn("代码配置错误:创建订单策略实现类{}未配置OrderTypeAnnotation注解", strategyClazz.getName());
continue;
}
}
// 支持多个事件类型
OrderTypeEnum typeEnum = annotation.orderType();
//String key = getKey(typeEnum.getOrderType());
if (orderStrategyBeanMap.containsKey(typeEnum)) {
logger.error("代码配置错误:一个订单类型({})只能对应一个创建订单策略实现{}", typeEnum, strategyClazz.getName());
throw new BizException(BizResultCode.ERR_SYSTEM.getCode(), "代码配置错误:一个订单类型(" + typeEnum + ")只能对应一个创建订单策略实现bean");
}
orderStrategyBeanMap.put(typeEnum, strategyClazz);
}
if (orderStrategyBeanMap.size() == 0) {
logger.warn("初始化创建订单策略集合失败");
}
}
}
}
4、实体类
public class Order {
private String buyer;
private String goodsName;
private Double price;
private Integer orderType;
//此处忽略get和set
}
5、业务层
接口
import com.hong.strategy.entity.Order;
public interface OrderService {
String handleOrder(Order order);
}
实现类
import com.hong.strategy.entity.Order;
import com.hong.strategy.service.OrderService;
import com.hong.strategy.strategys.config.HandlerOrderContext;
import com.hong.strategy.strategys.service.OrderStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class OrderServiceImpl implements OrderService {
private static final Logger logger = LoggerFactory.getLogger(HandlerOrderContext.class);
@Override
public String handleOrder(Order order) {
try {
// 根据订单类型获取对应的创建订单策略
OrderStrategy orderStrategy = HandlerOrderContext.getInstance(order.getOrderType());
String userInfo = orderStrategy.getUserInfo(order.getBuyer());
String goodsInfo = orderStrategy.getGoodsInfo(order.getGoodsName());
Double discount = orderStrategy.getDiscount();
String msg = "n购买人信息:" + userInfo +
"n商品信息:" + goodsInfo +
"n优惠金额:" + discount +
"n原价:" + order.getPrice() +
"n优惠后金额:" + (order.getPrice() - discount);
logger.info(msg);
return msg;
} catch (Exception e) {
return e.getMessage();
}
}
}
6、控制层
import com.hong.strategy.entity.Order;
import com.hong.strategy.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/handler")
public String handleOrder(Integer orderType) {
Order order = new Order();
order.setBuyer("小明");
order.setGoodsName("华为手机");
order.setPrice(3999.9);
order.setOrderType(orderType);
return orderService.handleOrder(order);
}
}
三、测试
四、源码地址(码云gitee):
annotation-strategy: SpringBoot 使用自定义注解实现策略模式【订单场景模拟】



