[设计模式] ------ 策略模式实战:java中替代if-else的大段逻辑

java中用策略模式替代if-else的大段逻辑

问题:

java本来是一门以面向对象为主的语言,但很多人嘴上说着java面向对象,然后除了表映射实体之外,其他的还是面向过程的思路。
就比如今天要说的,代码中大段大段的if-else判断,每个if-else代码块中又有很多复杂的逻辑,导致整个代码混乱不堪,让别人看到就感觉看到屎一样的代码一样。

那么,如何优雅的替代这些代码呢,其实有个设计模式(策略模式)就很好的解决了这个问题。

情景举例:

比如说订单处理,订单会有多个type状态,比如说
type=1的时候,就执行普通订单的逻辑;
type=2的时候,就执行满减促销订单的逻辑;
type=3的时候,就执行满返促销订单的逻辑;
等等,可能type会有数十种甚至更多种情况。

然后有些人就会开始if-else了,比如有如下的伪代码:

if(type=1){
	普通订单...(此处省略100多行处理逻辑)
}else if(type=2){
	满减促销订单...(此处省略100多行处理逻辑)
}else if(type=3){
	满返促销订单...(此处省略100多行处理逻辑)
}else if(type=n){
	...(此处省略几百上千行的逻辑)
}

做的好点的,会把if-else代码块中的逻辑,抽成一个个的方法,会稍微显的代码清晰许多,但这些都是面向过程的思想。
我认为,这种情况就应该用以下这种方式,即,用策略模式代替if-else,真正做到面向对象。
把每种不同类型的订单抽成一个个对象,然后通过不同的注解标识来区分调用。

用策略模式代替if-else:

首先,本次例子用的是Spring-Boot框架,亲测没问题。SpringMVC框架应该也是没问题的。
定义一个订单类,里面有type属性,type可以是"1"、“2”、“3”…
定义一个抽象类AbstractHandler,里面有个抽象方法handle,入参是订单类
定义一个注解HandlerType,有个value属性,value是几就代表这个注解注的这个类是什么类型的订单
定义普通类HandlerImpl01,实现AbstractHandler,代表普通订单,即@HandlerType(“1”);
定义普通类HandlerImpl02,实现AbstractHandler,代表满减促销订单,即@HandlerType(“2”);
定义普通类HandlerImpl03,实现AbstractHandler,代表满返促销订单,即@HandlerType(“3”);
定义一个初始化类HandlerProcessor,实现BeanFactoryPostProcessor,过程如下:
1、找到带有注解@HandlerType的类,
2、以注解的值为key,对应的类为value,存在一个map中
3、将这个map作为构造函数的参数,初始化HandlerContext,将HandlerContext注册到spring中成为一个单例bean。
很明显,目的就是为了保存不同type对应的不同类。
定义类HandlerContext,有个map类型的属性叫handlerMap,有个getInstance的方法,入参是type,返回AbstractHandler。
最后使用的时候,是先调用handlerContext.getInstance方法,根据type获取对应的AbstractHandler。
然后再调用他的handle方法,执行对应订单类型的处理逻辑。

具体代码如下:

//@Data是lombok的注解,为了省略不写get/set方法
@Data
public class OrderDTO {
    private String code;
    private BigDecimal price;
    /**
     * 订单类型
     * 1:普通订单
     * 2:满减订单
     * 3:满返订单
     */
    private String type;
}
public abstract class AbstractHandler {
    abstract public String handle(OrderDTO orderDTO);
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HandlerType {
    String value();
}
@Component
@HandlerType("1")
public class HandlerImpl01 extends AbstractHandler {
    @Override
    public String handle(OrderDTO orderDTO) {
        System.out.println("处理type为1的订单,orderDTO.type="+orderDTO.getType());
        return "success";
    }
}
@Component
@HandlerType("2")
public class HandlerImpl02 extends AbstractHandler {
    @Override
    public String handle(OrderDTO orderDTO) {
        System.out.println("处理type为2的订单,orderDTO.type="+orderDTO.getType());
        return "success";
    }
}
@Component
@HandlerType("3")
public class HandlerImpl03 extends AbstractHandler {
    @Override
    public String handle(OrderDTO orderDTO) {
        System.out.println("处理type为3的订单,orderDTO.type="+orderDTO.getType());
        return "success";
    }
}
@Component
@SuppressWarnings("unchecked")
public class HandlerProcessor implements BeanFactoryPostProcessor {
	//这里是具体的handler策略类的包的位置,为了后面的包扫描
    private static final String HANDLER_PACKAGE = "com.zs.handler";
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<String, Class> handlerMap = new HashMap<>();
		//包扫描
        ClassScaner.scan(HANDLER_PACKAGE,HandlerType.class).forEach(clazz ->{
            Annotation annotation = clazz.getAnnotation(HandlerType.class);
            HandlerType handlerType = (HandlerType) annotation;
            String type = handlerType.value();
            System.out.println(type);
            handlerMap.put(type,clazz);
        });
        HandlerContext handlerContext = new HandlerContext(handlerMap);
		//注册单例
        beanFactory.registerSingleton(HandlerContext.class.getName(),handlerContext);
    }
}
public class HandlerContext {
    private Map<String,Class> handlerMap;

    public HandlerContext(Map<String, Class> handlerMap) {
        this.handlerMap = handlerMap;
    }

    public AbstractHandler getInstance(String type){
        Class clazz = handlerMap.get(type);
        if(clazz == null){
            throw new IllegalArgumentException("没有type对应的处理器,type:"+type);
        }
        return (AbstractHandler)SpringContextUtils.getBean(clazz);
    }
}

定义接口:

public interface OrderService {
    /**
     * 根据订单类型处理订单
     * @param orderDTO
     * @return
     */
    String handle(OrderDTO orderDTO);
}

实现接口:

@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private HandlerContext handlerContext;

    @Override
    public String handle(OrderDTO orderDTO) {
        System.out.println("OrderServiceImpl handle 方法开始执行===");
        AbstractHandler handler = handlerContext.getInstance(orderDTO.getType());
        return handler.handle(orderDTO);
    }
}

包扫描的工具类:

public class ClassScaner implements ResourceLoaderAware {

    private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>();

    private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();

    private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);

    public ClassScaner() {

    }

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        this.metadataReaderFactory = new CachingMetadataReaderFactory( resourceLoader);
    }

//    public final ResourceLoader getResourceLoader() {
//        return this.resourcePatternResolver;
//    }

    public void addIncludeFilter(TypeFilter includeFilter) {
        this.includeFilters.add(includeFilter);
    }

//    public void addExcludeFilter(TypeFilter excludeFilter) {
//        this.excludeFilters.add(0, excludeFilter);
//    }

//    public void resetFilters(boolean useDefaultFilters) {
//        this.includeFilters.clear();
//        this.excludeFilters.clear();
//    }

    public static Set<Class> scan(String basePackage, Class<? extends Annotation>... annotations) {
        ClassScaner cs = new ClassScaner();
        for (Class anno : annotations)
            cs.addIncludeFilter(new AnnotationTypeFilter(anno));
        return cs.doScan(basePackage);
    }

//    public static Set scan(String[] basePackages, Class... annotations) {
//        ClassScaner cs = new ClassScaner();
//        for (Class anno : annotations)
//            cs.addIncludeFilter(new AnnotationTypeFilter(anno));
//        Set classes = new HashSet();
//        for (String s : basePackages)
//            classes.addAll(cs.doScan(s));
//        return classes;
//    }

    public Set<Class> doScan(String basePackage) {
        Set<Class> classes = new HashSet<Class>();
        try {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                    + org.springframework.util.ClassUtils
                    .convertClassNameToResourcePath(SystemPropertyUtils
                            .resolvePlaceholders(basePackage))
                    + "/**/*.class";
            Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);

            for (int i = 0; i < resources.length; i++) {
                Resource resource = resources[i];
                if (resource.isReadable()) {
                    MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                    if ((includeFilters.size() == 0 && excludeFilters.size() == 0)
                            || matches(metadataReader)) {
                        try {
                            classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }

                    }
                }
            }
        } catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "I/O failure during classpath scanning", ex);
        }
        return classes;
    }

    protected boolean matches(MetadataReader metadataReader) throws IOException {
        for (TypeFilter tf : this.excludeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return false;
            }
        }
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return true;
            }
        }
        return false;
    }
}

spring工具类,为了获取bean

@Component
public class SpringContextUtils implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;
    public static ApplicationContext getApplicationContext(){
        return applicationContext;
    }
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanId) {
        return (T) applicationContext.getBean(beanId);
    }
    public static <T> T getBean(Class<T> requiredType) {
        return (T) applicationContext.getBean(requiredType);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }
}

你可能感兴趣的:(设计模式,设计模式)