2020-06-21—策略模式代替if—else,注解实现

先说明情景:以订单处理为例,大体分PC端处理和mobile端处理,PC端分为扫码支付、信用卡支付,mobile端分为微信、支付宝处理。。。等等。

那么如何避免if-else呢?

策略模式注解实现

首先是订单Order类,和OrderService。

@Data
public class Order {
/**
* 订单来源
*/
private String source;
/**
* 支付方式
*/
private String payMethod;
/**
* 订单编号
*/
private String code;
/**
* 订单金额
*/
private BigDecimal amount;
}

假如对于不同来源(pc端、移动端)的订单需要不同的逻辑处理。项目中一般会有OrderService这样一个类,如下,里面有一坨if-else的逻辑,目的是根据订单的来源的做不同的处理。

@Service
public class OrderService {

public void orderService(Order order) {
if(order.getSource().equals("pc")){
// 处理pc端订单的逻辑
}else if(order.getSource().equals("mobile")){
// 处理移动端订单的逻辑
}else {
// 其他逻辑
}
}
}

大致的类图是这样的:

1.首先定义一个OrderHandler接口,此接口规定了处理订单的方法。

/**
* @author ellisonpei
*/
public interface OrderHandler {
void handle(Order order);
}

2.定义一个OrderHandlerType注解,来表示某个类是用来处理何种来源的订单。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface OrderHandlerType {
String source();
String payMethod();
}

但是我们还需要order的来源和支付方式与OrderHandlerType注解关联起来了。所以,现在我们就实现这么一个类


/**
* @author ellisonpei
*/
public class OrderHandlerTypeImp implements OrderHandlerType {

private String source;
private String payMethod;

OrderHandlerTypeImp(String source, String payMethod) {
this.source = source;
this.payMethod = payMethod;
}

@Override
public String source() {
return source;
}

@Override
public String payMethod() {
return payMethod;
}

@Override
public Class<? extends Annotation> annotationType() {
return OrderHandlerType.class;
}

@Override
public int hashCode() {
int hashCode = 0;
hashCode += (127 * "source".hashCode()) ^ source.hashCode();
hashCode += (127 * "payMethod".hashCode()) ^ payMethod.hashCode();
return hashCode;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof OrderHandlerType)) {
return false;
}
OrderHandlerType other = (OrderHandlerType) obj;
return source.equals(other.source()) && payMethod.equals(other.payMethod());
}
}

3.接下来就是实现pc端和移动端订单处理各自的handler,并加上我们所定义的OrderHandlerType注解。

/**
* @author ellisonpei
*/
@OrderHandlerType(source = "pc", payMethod = "cardPay")
public class PCHandler implements OrderHandler {
@Override
public void handle(Order order) {
System.out.println("处理PC端, cardPay订单!!");
}
}

/**
* @author ellisonpei
*/
@OrderHandlerType(source = "mobile", payMethod = "weChat")
public class WeChatHandler implements OrderHandler {
@Override
public void handle(Order order) {
System.out.println("微信支付处理了订单");
}
}

/**
* @author ellisonpei
*/
@OrderHandlerType(source = "mobile", payMethod = "airPay")
public class AirPayHandler implements OrderHandler {
@Override
public void handle(Order order) {
System.out.println("支付宝处理了订单");
}
}


4.以上准备就绪后,就是向spring容器中注入各种订单处理的handler,并在OrderService.orderService方法中,通过策略(订单来源)去决定选择哪一个OrderHandler去处理订单。我们可以这样做:

/**
* @author ellisonpei
*/
@Service
public class OrderService {

private Map<OrderHandlerType,OrderHandler> orderHandlerMap;

@Autowired
public void setOrderHandleMap(List<OrderHandler> orderHandlers) {
// 注入各种类型的订单处理类
orderHandlerMap = orderHandlers.stream().collect(
Collectors.toMap(orderHandler -> AnnotationUtils.findAnnotation(orderHandler.getClass(), OrderHandlerType.class),
v -> v,(v1, v2) -> v1));
}

public void orderService(Order order) {
// ...一些前置处理
System.out.println("前置处理方法");
// 通过订单来源以及支付方式来 确定对应的handler
OrderHandlerType orderHandlerType = new OrderHandlerTypeImp(order.getSource(), order.getPayMethod());
OrderHandler orderHandler = orderHandlerMap.get(orderHandlerType);
orderHandler.handle(order);

// ...一些后置处理
System.out.println("后置处理方法");
}
}

5、下面我们进行测试

编写单元测试:

@SpringBootTest
class StrategydemoApplicationTests {
@Autowired
private OrderService orderService;

@Test
public void test(){
Order order = new Order();
order.setSource("mobile");
order.setPayMethod("airPay");
order.setAmount(new BigDecimal(200));
order.setCode("1020202020");
orderService.orderService(order);
}
}

测试结果:

代码地址:https://gitee.com/ellisonpei/designer

2020-06-21—策略模式代替if—else,注解实现

https://peialan.github.io/2020/06/21/2020-06-21—策略模式-注解实现/

发布于

2020-06-21

更新于

2022-03-25

许可协议

评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...