=<订单类型, 创建订单服务策略class>
*
* 注:此集合只存放OrderStrategy的子类class,对应的实例交由spring容器来管理
*/
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;
}
/**
* 获取创建订单策略实例
*
* @param orderType 订单类型
*/
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、实体类
```java
/**
* 订单-实体类
*
* @author xiehongwei
* @date 2021/10/08
*/
public class Order {
/**
* 购买人
*/
private String buyer;
/**
* 商品名称
*/
private String goodsName;
/**
* 金额
*/
private Double price;
/**
* 订单类型
*/
private Integer orderType;
//此处忽略get和set
}
```
## 5、业务层
### 接口
```java
import com.hong.strategy.entity.Order;
/**
* 订单-业务层
*
* @author xiehongwei
* @date 2021/10/08
*/
public interface OrderService {
String handleOrder(Order order);
}
```
### 实现类
```java
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;
/**
* 订单-实现类
*
* @author xiehongwei
* @date 2021/10/08
*/
@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、控制层
```java
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;
/**
* 订单-控制层
*
* @author xiehongwei
* @date 2021/10/08
*/
@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);
}
}
```
# 三、测试
## 淘宝订单类型-测试结果
重写了【获取商品信息】接口,在商品名称前加上了【淘宝】字样
未重写【获取优惠金额】接口

## 京东订单类型-测试结果
重写了【获取商品信息】接口,在商品名称前加上了【京东】字样
重写了【获取优惠金额】接口,优惠金额50元

## 苏宁订单类型-测试结果
重写了【获取商品信息】接口,在商品名称前加上了【苏宁】字样
重写了【获取优惠金额】接口,优惠金额100元

# 四、源码地址(码云gitee):
[annotation-strategy: SpringBoot 使用自定义注解实现策略模式【订单场景模拟】](https://gitee.com/custom116/annotation-strategy)