美文网首页
策略模式

策略模式

作者: jjjjxd | 来源:发表于2018-05-14 22:12 被阅读0次

    本质:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换,解除使用算法者之间与算法的耦合(当遇到多个if-else或switch使用)

    实际使用: 在之前做的一个项目中有将xml转换成HashMap,xml类型有多种,不同种类型xml格式不同,因此有不同的转换方法,如果不用设计模式则必须使用大量if-else来判断xml类型,下面使用策略模式进行改造:

    image image image image image

    问题:在选择策略是也会遇到大量if-else

    image

    在选择策略时,使用 简单工厂模式,可以看到当报文类型更多时,if-else体积也会变得庞大,并且新增策略时就必须修改策略工厂,这与开放封闭-原则也不符,目前我们项目采用的是将策略注入到Spring容器当中,按照beanName查找策略,这种方法比较好想,但是如果策略不能和bean建立一一对应关系,则可以使用自定义注解实现

    package com.msgconverter;
    
    import java.io.File;
    import java.io.FileFilter;
    import java.net.URISyntaxException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author jxdong
     * @date 2018/5/13
     */
    public class MsgFactory {
        private static final String CONVERTER_PACKAGE = "com.msgconverter";//策略类所在的包
        private static List<Class<? extends MsgConverter>> CONVERTER_LIST;//策略列表
        private ClassLoader classLoader = getClass().getClassLoader();//我们加载策略时的类加载器,我们任何类运行时信息必须来自该类加载器
    
        //不允许通过构造函数实例工厂
        private MsgFactory() {
            init();
        }
    
        private void init() {
            CONVERTER_LIST = new ArrayList<>();
            File[] classFile = getClassFiles();
            Class msgConverterClazz = null;
            try {
                msgConverterClazz = classLoader.loadClass(MsgConverter.class.getName());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("未找到策略接口");
            }
            for (File file : classFile) {
                try {
                    //载入包下的类
                    Class<?> clazz = classLoader.loadClass(CONVERTER_PACKAGE + "." + file.getName().replace(".class", ""));
                    //判断是否是MsgConverter的实现类并且不是MsgConverter它本身,满足的话加入到策略列表
                    if (MsgConverter.class.isAssignableFrom(clazz) && clazz != msgConverterClazz) {
                        CONVERTER_LIST.add((Class<? extends MsgConverter>) clazz);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
    
            }
        }
    
        public MsgConverter getMsgConverter(String msgType) throws Exception {
            //假设类型有Pay Refund两种
            for (Class<? extends MsgConverter> clazz : CONVERTER_LIST) {
                MsgType msgTypeAnnotation = clazz.getDeclaredAnnotation(MsgType.class);
                if (null != msgTypeAnnotation) {
                    if (msgType.equals(msgTypeAnnotation.msgType())) {
                        return clazz.newInstance();
                    }
                } else {
                    throw new Exception("策略获取失败");
                }
            }
            return null;
        }
    
        private File[] getClassFiles() {
            try {
                File file = new File(classLoader.getResource(CONVERTER_PACKAGE.replace(".", "/")).toURI());
                return file.listFiles(new FileFilter() {
                    @Override
                    public boolean accept(File pathname) {
                        if (pathname.getName().endsWith(".class")) {//只扫描class文件
                            return true;
                        }
                        return false;
                    }
                });
            } catch (URISyntaxException e) {
                throw new RuntimeException("未找到策略");
            }
    
    
        }
    
        //单例工厂
        public static class MsgFactoryHolder {
            private static MsgFactory INSTANCE = new MsgFactory();
    
            public static MsgFactory getInstance() {
                return INSTANCE;
            }
    
        }
    
    
    }
    

    在看策略模式的时候看到一个有趣的问题,上面的代码并不能实现多个策略重叠(本例中没有该需求),如果有则进行改造

    相关文章

      网友评论

          本文标题:策略模式

          本文链接:https://www.haomeiwen.com/subject/xbrsdftx.html