需求: 这里虚拟一个业务需求,让大家容易理解。假设有一个订单系统,里面的一个功能是根据订单的不同类型作出不同的处理。

 

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那些事儿”

posted on 2020-01-18 23:10  显示账号  阅读(2317)  评论(0编辑  收藏  举报