介绍
定义一系列的算法,并且使他们之间可以相互替换。该模式使得算法可独立于它的使用者而变化。
需求
假定我们在订单后台处理类需要处理不同类型的订单,含普通订单,支付宝订单,微信订单
订单实体类
package com.strategy.dto;
/**
* 订单信息
* @author Administrator
*
*/
public class OrderDto {
/**
* 1.普通订单
* 2.微信订单
* 3.支付宝订单
*/
private String type;
private String price;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
传统实现
需要根据订单类型写一堆的if…else…语句
package com.strategy.service.impl;
import com.strategy.dto.OrderDto;
import com.strategy.service.IOrderService;
/**
* 订单处理类
* @author Administrator
*
*/
public class OrderServiceImpl implements IOrderService{
@Override
public String handle(OrderDto orderDto) {
String type = orderDto.getType();
if ("1".equals(type))
{
return "处理普通订单";
}
else if ("2".equals(type))
{
return "处理微信订单";
}
else if ("3".equals(type))
{
return "处理支付宝订单";
}
return null;
}
}
策略模式实现
package com.strategy.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import com.strategy.common.HandleContext;
import com.strategy.dto.OrderDto;
import com.strategy.handle.AbstractHandler;
import com.strategy.service.IOrderService;
/**
* 基于策略模式实现的订单处理类
* @author Administrator
*
*/
@Service
@Primary
public class OrderServiceImplV2 implements IOrderService{
@Autowired
private HandleContext handleContext;
@Override
public String handle(OrderDto orderDto) {
AbstractHandler abstractHandler = handleContext.getInstance(orderDto.getType());
return abstractHandler.handle(orderDto);
}
}
从V2版本的订单处理类可以看出,我们注入了处理器上下文orderContext,其实现见下文。我们从中获取了一个抽象的处理器,调用其处理逻辑。
而真正的订单处理逻辑是在处理器类中实现的。有多少订单类型,就有多少处理器类。
package com.strategy.handle;
import org.springframework.stereotype.Component;
import com.strategy.common.HandleType;
import com.strategy.dto.OrderDto;
@Component
@HandleType("1")
public class NormalHandle extends AbstractHandler{
@Override
public String handle(OrderDto orderDto) {
return "处理普通订单";
}
}
package com.strategy.handle;
import org.springframework.stereotype.Component;
import com.strategy.common.HandleType;
import com.strategy.dto.OrderDto;
@Component
@HandleType("2")
public class WeechatOrder extends AbstractHandler {
@Override
public String handle(OrderDto orderDto) {
return "处理微信订单";
}
}
package com.strategy.handle;
import org.springframework.stereotype.Component;
import com.strategy.common.HandleType;
import com.strategy.dto.OrderDto;
@Component
@HandleType("3")
public class AlipayOrder extends AbstractHandler {
@Override
public String handle(OrderDto orderDto) {
return "处理支付宝订单";
}
}
每个处理器都需要添加到Ioc容器,因此需加上@Component注解,其次需要加上一个自定义注解@HandleType,用于标识处理器能够处理哪种类型的订单,最后继承AbstractHandler ,实现各自的业务逻辑。
自定义注解
package com.strategy.common;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HandleType {
String value();
}
抽象处理器类
package com.strategy.handle;
import com.strategy.dto.OrderDto;
/**
* @author Administrator
*
*/
public abstract class AbstractHandler {
public abstract String handle(OrderDto orderDto);
}
自定义注解和 抽象处理器比较简单,如何将HandleContext注入到容器,并且能够根据订单类型找到对应的处理器呢
详细步骤:
- 容器启动时扫描指定包的标有@HandleType的类
- 将注解中的value值作为key,对应的类作为value,保存在Map
- 以上面的map作为构造函数参数,初始化HandlleContext,将其注册到Spring Ioc容器
我们将上述步骤的功能封装在HandleProcessor类中,
package com.strategy.common;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.cent.scanner.core.scanner.ClassScanner;
import org.cent.scanner.core.scanner.impl.DefaultClassScanner;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/**
* 注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息
* @author Administrator
*
*/
@Component
public class HandleProcessor implements BeanFactoryPostProcessor{
private ClassScanner classScanner = new DefaultClassScanner();
/*
* 扫描定义了@HandleType的类,实例化HandleContext,并注入到Ioc容器
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<String, Class> handleMap = new HashMap<String, Class>();
classScanner.scanByAnno(Arrays.asList("com.strategy"), HandleType.class).forEach(clazz -> {
HandleType handleType = (HandleType) clazz.getAnnotation(HandleType.class);
String value = handleType.value();
handleMap.put(value, clazz);
});;
HandleContext handleContext = new HandleContext(handleMap, beanFactory);
beanFactory.registerSingleton(handleContext.getClass().getName(), handleContext);
}
}
再来看看HandleContext如何获取到处理器
package com.strategy.common;
import java.util.Map;
import org.springframework.beans.factory.ListableBeanFactory;
import com.strategy.handle.AbstractHandler;
public class HandleContext{
private Map<String, Class> handleMap;
private ListableBeanFactory beanFactory;
public HandleContext(Map<String, Class> handleMap, ListableBeanFactory beanFactory) {
this.handleMap = handleMap;
this.beanFactory = beanFactory;
}
public AbstractHandler getInstance(String type) {
Class class1 = handleMap.get(type);
if (null == class1)
{
throw new IllegalArgumentException();
}
return (AbstractHandler) beanFactory.getBean(class1);
}
}
总结
利用策略模式可以简化繁杂的if…else…代码,方便维护,实现优雅。