策略模式

介绍

定义一系列的算法,并且使他们之间可以相互替换。该模式使得算法可独立于它的使用者而变化。

需求

假定我们在订单后台处理类需要处理不同类型的订单,含普通订单,支付宝订单,微信订单

订单实体类

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注入到容器,并且能够根据订单类型找到对应的处理器呢
详细步骤:

  1. 容器启动时扫描指定包的标有@HandleType的类
  2. 将注解中的value值作为key,对应的类作为value,保存在Map
  3. 以上面的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…代码,方便维护,实现优雅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值