前言

物流行业中,通常会波及到EDI报文(XML格式文件)传输和回执接管,每发送一份EDI报文,后续都会收到与之关联的回执(标识该数据在第三方零碎中的流转状态)。

这里枚举几种回执类型:MT1101、MT2101、MT4101、MT8104、MT8105、MT9999,零碎在收到不同的回执报文后,会执行对应的业务逻辑解决。当然,理论业务场景并没有那么抽象,这里以回执解决为演示案例。

模仿一个回执类

@Datapublic class Receipt {    /**     * 回执信息     */    String message;    /**     * 回执类型(`MT1101、MT2101、MT4101、MT8104、MT8105、MT9999`)     */    String type;}

模仿一个回执生成器

public class ReceiptBuilder {    public static List<Receipt> generateReceiptList(){        //间接模仿一堆回执对象        List<Receipt> receiptList = new ArrayList<>();        receiptList.add(new Receipt("我是MT2101回执喔","MT2101"));        receiptList.add(new Receipt("我是MT1101回执喔","MT1101"));        receiptList.add(new Receipt("我是MT8104回执喔","MT8104"));        receiptList.add(new Receipt("我是MT9999回执喔","MT9999"));        //......        return receiptList;    }}

传统做法-if-else分支

List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();//循环解决for (Receipt receipt : receiptList) {    if (StringUtils.equals("MT2101",receipt.getType())) {        System.out.println("接管到MT2101回执");        System.out.println("解析回执内容");        System.out.println("执行业务逻辑");    } else if (StringUtils.equals("MT1101",receipt.getType())) {        System.out.println("接管到MT1101回执");        System.out.println("解析回执内容");        System.out.println("执行业务逻辑");    } else if (StringUtils.equals("MT8104",receipt.getType())) {        System.out.println("接管到MT8104回执");        System.out.println("解析回执内容");        System.out.println("执行业务逻辑");    } else if (StringUtils.equals("MT9999",receipt.getType())) {        System.out.println("接管到MT9999回执");        System.out.println("解析回执内容");        System.out.println("执行业务逻辑");        System.out.println("推送邮件");    }    // ......将来可能还有好多个else if}

在遇到if-else的分支业务逻辑比较复杂时,咱们都习惯于将其抽出一个办法或者封装成一个对象去调用,这样整个if-else构造就不会显得太臃肿。

就下面例子,当回执的类型越来越多时,分支else if 就会越来越多,每减少一个回执类型,就须要批改或增加if-else分支,违反了开闭准则(对扩大凋谢,对批改敞开)

策略模式+Map字典
咱们晓得, 策略模式的目标是封装一系列的算法,它们具备共性,能够互相替换,也就是说让算法独立于应用它的客户端而独立变动,客户端仅仅依赖于策略接口 。

在上述场景中,咱们能够把if-else分支的业务逻辑抽取为各种策略,然而不可避免的是仍然须要客户端写一些if-else进行策略抉择的逻辑,咱们能够将这段逻辑抽取到工厂类中去,这就是策略模式+简略工厂,代码如下

策略接口

/** * @Description: 回执解决策略接口 * @Auther: wuzhazha */public interface IReceiptHandleStrategy {    void handleReceipt(Receipt receipt);}

策略接口实现类,也就是具体的解决者

public class Mt2101ReceiptHandleStrategy implements IReceiptHandleStrategy {    @Override    public void handleReceipt(Receipt receipt) {        System.out.println("解析报文MT2101:" + receipt.getMessage());    }}public class Mt1101ReceiptHandleStrategy implements IReceiptHandleStrategy {    @Override    public void handleReceipt(Receipt receipt) {        System.out.println("解析报文MT1101:" + receipt.getMessage());    }}public class Mt8104ReceiptHandleStrategy implements IReceiptHandleStrategy {    @Override    public void handleReceipt(Receipt receipt) {        System.out.println("解析报文MT8104:" + receipt.getMessage());    }}public class Mt9999ReceiptHandleStrategy implements IReceiptHandleStrategy {    @Override    public void handleReceipt(Receipt receipt) {        System.out.println("解析报文MT9999:" + receipt.getMessage());    }}

策略上下文类(策略接口的持有者)

/** * @Description: 上下文类,持有策略接口 * @Auther: wuzhazha */public class ReceiptStrategyContext {    private IReceiptHandleStrategy receiptHandleStrategy;    /**     * 设置策略接口     * @param receiptHandleStrategy     */    public void setReceiptHandleStrategy(IReceiptHandleStrategy receiptHandleStrategy) {        this.receiptHandleStrategy = receiptHandleStrategy;    }    public void handleReceipt(Receipt receipt){        if (receiptHandleStrategy != null) {             receiptHandleStrategy.handleReceipt(receipt);        }    }}

策略工厂

/** * @Description: 策略工厂 * @Auther: wuzhazha */public class ReceiptHandleStrategyFactory {    private ReceiptHandleStrategyFactory(){}    public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){        IReceiptHandleStrategy receiptHandleStrategy = null;        if (StringUtils.equals("MT2101",receiptType)) {            receiptHandleStrategy = new Mt2101ReceiptHandleStrategy();        } else if (StringUtils.equals("MT8104",receiptType)) {            receiptHandleStrategy = new Mt8104ReceiptHandleStrategy();        }        return receiptHandleStrategy;    }}

客户端

public class Client {    public static void main(String[] args) {        //模仿回执        List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();        //策略上下文        ReceiptStrategyContext receiptStrategyContext = new ReceiptStrategyContext();        for (Receipt receipt : receiptList) {            //获取并设置策略            IReceiptHandleStrategy receiptHandleStrategy = ReceiptHandleStrategyFactory.getReceiptHandleStrategy(receipt.getType());            receiptStrategyContext.setReceiptHandleStrategy(receiptHandleStrategy);            //执行策略            receiptStrategyContext.handleReceipt(receipt);        }    }}

解析报文MT2101:我是MT2101回执报文喔 解析报文MT8104:我是MT8104回执报文喔

因为咱们的目标是打消if-else,那么这里须要将ReceiptHandleStrategyFactory策略工厂进行革新下,采纳字典的形式寄存我的策略,而Map具备key-value构造,采纳Map是个不错抉择。

略微革新下,代码如下

/** * @Description: 策略工厂 * @Auther: wuzhazha */public class ReceiptHandleStrategyFactory {    private static Map<String,IReceiptHandleStrategy> receiptHandleStrategyMap;    private ReceiptHandleStrategyFactory(){        this.receiptHandleStrategyMap = new HashMap<>();        this.receiptHandleStrategyMap.put("MT2101",new Mt2101ReceiptHandleStrategy());        this.receiptHandleStrategyMap.put("MT8104",new Mt8104ReceiptHandleStrategy());    }    public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){        return receiptHandleStrategyMap.get(receiptType);    }}

通过对策略模式+简略工厂计划的革新,咱们曾经打消了if-else的构造,每当新来了一种回执,只须要增加新的回执解决策略,并批改ReceiptHandleStrategyFactory中的Map汇合。

如果要使得程序合乎开闭准则,则须要调整ReceiptHandleStrategyFactory中解决策略的获取形式,通过反射的形式,获取指定包下的所有IReceiptHandleStrategy实现类,而后放到字典Map中去。

责任链模式

责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的援用而连接起来造成一条链。申请在这个链上传递,直到链上的某一个对象决定解决此申请。

收回这个申请的客户端并不知道链上的哪一个对象最终解决这个申请,这使得零碎能够在不影响客户端的状况下动静地从新组织和调配责任

回执解决者接口

/** * @Description: 形象回执解决者接口 * @Auther: wuzhazha */public interface IReceiptHandler {    void handleReceipt(Receipt receipt,IReceiptHandleChain handleChain);}

责任链接口

/** * @Description: 责任链接口 * @Auther: wuzhazha */public interface IReceiptHandleChain {    void handleReceipt(Receipt receipt);}

责任链接口实现类

/** * @Description: 责任链实现类 * @Auther: wuzhazha */public class ReceiptHandleChain implements IReceiptHandleChain {    //记录以后解决者地位    private int index = 0;    //解决者汇合    private static List<IReceiptHandler> receiptHandlerList;    static {        //从容器中获取处理器对象        receiptHandlerList = ReceiptHandlerContainer.getReceiptHandlerList();    }    @Override    public void handleReceipt(Receipt receipt) {        if (receiptHandlerList !=null && receiptHandlerList.size() > 0) {            if (index != receiptHandlerList.size()) {                IReceiptHandler receiptHandler = receiptHandlerList.get(index++);                receiptHandler.handleReceipt(receipt,this);            }        }    }}

具体回执解决者

public class Mt2101ReceiptHandler implements IReceiptHandler {    @Override    public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {        if (StringUtils.equals("MT2101",receipt.getType())) {            System.out.println("解析报文MT2101:" + receipt.getMessage());        }        //解决不了该回执就往下传递        else {            handleChain.handleReceipt(receipt);        }    }}public class Mt8104ReceiptHandler implements IReceiptHandler {    @Override    public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {        if (StringUtils.equals("MT8104",receipt.getType())) {            System.out.println("解析报文MT8104:" + receipt.getMessage());        }        //解决不了该回执就往下传递        else {            handleChain.handleReceipt(receipt);        }    }}

责任链解决者容器(如果采纳spring,则能够通过依赖注入的形式获取到IReceiptHandler的子类对象)

/** * @Description: 解决者容器 * @Auther: wuzhazha */public class ReceiptHandlerContainer {    private ReceiptHandlerContainer(){}    public static List<IReceiptHandler> getReceiptHandlerList(){        List<IReceiptHandler> receiptHandlerList = new ArrayList<>();        receiptHandlerList.add(new Mt2101ReceiptHandler());        receiptHandlerList.add(new Mt8104ReceiptHandler());        return receiptHandlerList;    }}

客户端

public class Client {    public static void main(String[] args) {        //模仿回执        List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();        for (Receipt receipt : receiptList) {            //回执解决链对象            ReceiptHandleChain receiptHandleChain = new ReceiptHandleChain();            receiptHandleChain.handleReceipt(receipt);        }    }}

解析报文MT2101:我是MT2101回执报文喔 解析报文MT8104:我是MT8104回执报文喔

通过责任链的解决形式,if-else构造也被咱们打消了,每当新来了一种回执,只须要增加IReceiptHandler实现类并批改ReceiptHandlerContainer解决者容器即可,如果要使得程序合乎开闭准则,则须要调整ReceiptHandlerContainer中解决者的获取形式,通过反射的形式,获取指定包下的所有IReceiptHandler实现类。

这里应用到了一个反射工具类,用于获取指定接口的所有实现类

/** * @Description: 反射工具类 * @Auther: wuzhazha */public class ReflectionUtil {    /**     * 定义类汇合(用于寄存所有加载的类)     */    private static final Set<Class<?>> CLASS_SET;    static {        //指定加载包门路        CLASS_SET = getClassSet("com.yaolong");    }    /**     * 获取类加载器     * @return     */    public static ClassLoader getClassLoader(){        return Thread.currentThread().getContextClassLoader();    }    /**     * 加载类     * @param className 类全限定名称     * @param isInitialized 是否在加载实现后执行动态代码块     * @return     */    public static Class<?> loadClass(String className,boolean isInitialized) {        Class<?> cls;        try {            cls = Class.forName(className,isInitialized,getClassLoader());        } catch (ClassNotFoundException e) {            throw new RuntimeException(e);        }        return cls;    }    public static Class<?> loadClass(String className) {        return loadClass(className,true);    }    /**     * 获取指定包下所有类     * @param packageName     * @return     */    public static Set<Class<?>> getClassSet(String packageName) {        Set<Class<?>> classSet = new HashSet<>();        try {            Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".","/"));            while (urls.hasMoreElements()) {                URL url = urls.nextElement();                if (url != null) {                    String protocol = url.getProtocol();                    if (protocol.equals("file")) {                        String packagePath = url.getPath().replace("%20","");                        addClass(classSet,packagePath,packageName);                    } else if (protocol.equals("jar")) {                        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();                        if (jarURLConnection != null) {                            JarFile jarFile = jarURLConnection.getJarFile();                            if (jarFile != null) {                                Enumeration<JarEntry> jarEntries = jarFile.entries();                                while (jarEntries.hasMoreElements()) {                                    JarEntry jarEntry = jarEntries.nextElement();                                    String jarEntryName = jarEntry.getName();                                    if (jarEntryName.endsWith(".class")) {                                        String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");                                        doAddClass(classSet,className);                                    }                                }                            }                        }                    }                }            }        } catch (IOException e) {            throw new RuntimeException(e);        }        return classSet;    }    private static void doAddClass(Set<Class<?>> classSet, String className) {        Class<?> cls = loadClass(className,false);        classSet.add(cls);    }    private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {        final File[] files = new File(packagePath).listFiles(new FileFilter() {            @Override            public boolean accept(File file) {                return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();            }        });        for (File file : files) {            String fileName = file.getName();            if (file.isFile()) {                String className = fileName.substring(0, fileName.lastIndexOf("."));                if (StringUtils.isNotEmpty(packageName)) {                    className = packageName + "." + className;                }                doAddClass(classSet,className);            } else {                String subPackagePath = fileName;                if (StringUtils.isNotEmpty(packagePath)) {                    subPackagePath = packagePath + "/" + subPackagePath;                }                String subPackageName = fileName;                if (StringUtils.isNotEmpty(packageName)) {                    subPackageName = packageName + "." + subPackageName;                }                addClass(classSet,subPackagePath,subPackageName);            }        }    }    public static Set<Class<?>> getClassSet() {        return CLASS_SET;    }    /**     * 获取利用包名下某父类(或接口)的所有子类(或实现类)     * @param superClass     * @return     */    public static Set<Class<?>> getClassSetBySuper(Class<?> superClass) {        Set<Class<?>> classSet = new HashSet<>();        for (Class<?> cls : CLASS_SET) {            if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)) {                classSet.add(cls);            }        }        return classSet;    }    /**     * 获取利用包名下带有某注解的类     * @param annotationClass     * @return     */    public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass) {        Set<Class<?>> classSet = new HashSet<>();        for (Class<?> cls : CLASS_SET) {            if (cls.isAnnotationPresent(annotationClass)) {                classSet.add(cls);            }        }        return classSet;    }}

接下来革新ReceiptHandlerContainer

public class ReceiptHandlerContainer {    private ReceiptHandlerContainer(){}    public static List<IReceiptHandler> getReceiptHandlerList(){        List<IReceiptHandler> receiptHandlerList = new ArrayList<>();        //获取IReceiptHandler接口的实现类        Set<Class<?>> classList = ReflectionUtil.getClassSetBySuper(IReceiptHandler.class);        if (classList != null && classList.size() > 0) {            for (Class<?> clazz : classList) {                try {                    receiptHandlerList.add((IReceiptHandler)clazz.newInstance());                } catch ( Exception e) {                    e.printStackTrace();                }            }        }        return receiptHandlerList;    }}

至此,该计划完满合乎了开闭准则,如果新增一个回执类型,只须要增加一个新的回执处理器即可,无需做其它改变。如新加了MT6666的回执,代码如下

public class Mt6666ReceiptHandler implements IReceiptHandler {    @Override    public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {        if (StringUtils.equals("MT6666",receipt.getType())) {            System.out.println("解析报文MT6666:" + receipt.getMessage());        }        //解决不了该回执就往下传递        else {            handleChain.handleReceipt(receipt);        }    }}

策略模式+注解

此计划其实和上述没有太大异同,为了能合乎开闭准则,通过自定义注解的形式,标记解决者类,而后反射获取到该类汇合,放到Map容器中,这里不再赘述

小结

if-else或switch case 这种分支判断的形式对于分支逻辑不多的简略业务,还是直观高效的。对于业务简单,分支逻辑多,采纳适当的模式技巧,会让代码更加清晰,容易保护,但同时类或办法数量也是倍增的。咱们须要对业务做好充沛剖析,防止一上来就设计模式,防止适度设计!

起源:cnblogs.com/DiDi516/p/11787257.html