Design patterns used instead if-else

Design patterns used instead if-else

Foreword

Logistics industry, typically involves the EDI message (XML format) received receipt and transmission, each EDI send a packet, receives a subsequent receipt associated (state identifies the data stream in the third-party system ). Several types enumerated herein receipt: MT1101、MT2101、MT4101、MT8104、MT8105、MT9999the system after receiving different acknowledgment packets, performs processing corresponding to the business logic. Of course, the actual business scenarios and not so general, here with receipt processing for presentations Case

  • Simulate a receipt class
@Data
public class Receipt {

    /**
     * 回执信息
     */
    String message;

    /**
     * 回执类型(`MT1101、MT2101、MT4101、MT8104、MT8105、MT9999`)
     */
    String type;

}
  • Simulation of a receipt generator
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;
    }
}


Traditional practices -if-else branch

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
}

In the face of if-else branch business logic more complex, we are accustomed to draw out a method or packaged as an object to call, so the whole if-else structure would not look too bloated. On the above example, when the type of receipt rises, else if the branch will be more and more, each additional receipt type, you need to modify or add if-else branch, in violation of the principle of opening and closing (open to extension, for modify close)


Strategy Mode + Map Dictionary

We know that the purpose of the strategy pattern is to encapsulate a series of algorithms, they have in common, we can replace each other, so that the algorithm that is independent of the use of its clients and independent changes, client rely solely on policy interface. In the above scenario, we can put the if-else branch of the business logic to extract a variety of strategies, but it is inevitable that the client still need to write some if-else logic for policy choice, we can extract this logic to the factory class to go, this is the strategy pattern + simple factory , the code is as follows

  • Policy Interface
/**
 * @Description: 回执处理策略接口
 * @Auther: wuzhazha
 */
public interface IReceiptHandleStrategy {

    void handleReceipt(Receipt receipt);

}
  • Policy interface class, which is a specific handler
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());
    }

}
  • Policy context class (policy holder interface)
/**
 * @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);   
        }
    }
}
  • Strategy factory
/**
 * @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;
    }
}
  • Client
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);
        }
    }
}

Parses the message MT2101: I am a MT2101 receipt message Oh,
parse messages MT8104: I am a MT8104 receipt message Oh

Since our goal is to eliminate if-else, this will require ReceiptHandleStrategyFactorypolicy reform at the factory, using a dictionary way to store my strategy, and Map with key-value structure, using the Map is a good choice. Under slightly modified, as follows

/**
 * @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);
    }
}

After the transformation of the mode of strategy + simple plant solutions, we have eliminated the structure if-else whenever a new receipt, just add a new receipt processing strategies, and modify ReceiptHandleStrategyFactoryMap collection. If you want to make the program consistent with the principle of opening and closing, we need to adjust the ReceiptHandleStrategyFactoryacquisition mode processing strategy, by way of reflection , get all under the specified package IReceiptHandleStrategyimplementation class, then go into the dictionary Map.


Chain of Responsibility pattern

Chain of Responsibility pattern is an object-behavior patterns of. In the chain of responsibility pattern, many objects of each object reference to them at home and connected together to form a chain. In this chain transfer request until a certain object on the chain determination process request. Issued this request client does not know which object on the chains are ultimately process the request, so that it can not affect the dynamic system re-organization and distribution of responsibility in the case of the client

  • Receipt processing Interface
/**
 * @Description: 抽象回执处理者接口
 * @Auther: wuzhazha
 */
public interface IReceiptHandler {

    void handleReceipt(Receipt receipt,IReceiptHandleChain handleChain);

}
  • Responsibility chain interface
/**
 * @Description: 责任链接口
 * @Auther: wuzhazha
 */
public interface IReceiptHandleChain {

    void handleReceipt(Receipt receipt);
}
  • Responsibility chain interface implementation class
/**
 * @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);
            }
        }
    }
}
  • Specific receipt handler
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);
        }
    }
}
  • Chain of responsibility by processing vessel (if spring, may be injection-dependent manner by the acquired IReceiptHandlersub-class object)
/**
 * @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;
    }

}
  • Client
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);
        }
    }
}

Parses the message MT2101: I am a MT2101 receipt message Oh,
parse messages MT8104: I am a MT8104 receipt message Oh

By handling the chain of responsibility, if-else structure is also eliminated us, every time a new receipt, just add IReceiptHandlerthe implementation class and modify the ReceiptHandlerContainerhandler container can, if you want to make the program consistent with the principle of opening and closing, you need to adjustment ReceiptHandlerContainerof handlers acquisition mode, by way of reflection , all acquired in the specified package IReceiptHandlerimplementation class

As used herein, the reflection of a tool class, for obtaining all the specified interface implementation class

/**
 * @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;
    }

}

The next transformationReceiptHandlerContainer

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;
    }

}

So far, the program perfectly in line with the principle of opening and closing, if a new type of receipt, just add a new receipt processor without the need to make other changes. The MT6666 receipt of a newly-added, as follows

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);
        }
    }
}


Strategy Mode + Notes

This fact, and the program is not much above the similarities and differences, in order to comply with the principle of opening and closing, by way of custom annotations, marking handler class, then the class reflected acquired collection container into the Map, is not repeated here


summary

or if-else switch case this branch is determined way branching logic for small business simple, intuitive or efficient. For complex operations, multi-branching logic, using techniques appropriate mode, makes the code more clear, easy to maintain, but at the same time the number of classes or methods are multiplied. We need to do a full analysis of the business, avoid one up on design patterns, avoid over-engineering!

Guess you like

Origin www.cnblogs.com/DiDi516/p/11787257.html