Design pattern to replace if-else

Preface #

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

Copy

``@Data
public class Receipt {

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

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

}``

  • Simulation of a receipt generator

Copy

`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 #

Copy

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

Copy

`/**

  • @Description: Receipt processing strategy Interface
  • @Auther: wuzhazha
    */
    public interface IReceiptHandleStrategy {

    void handleReceipt(Receipt receipt);

}`

  • Policy interface class, which is a specific handler

Copy

`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)

Copy

`/**

  • @Description: context class, hold strategy Interface
  • @Auther: wuzhazha
    */
    public class ReceiptStrategyContext {

    private IReceiptHandleStrategy receiptHandleStrategy;

    /**
    • Setting Policy Interface
    • @param receiptHandleStrategy
      */
      public void setReceiptHandleStrategy(IReceiptHandleStrategy receiptHandleStrategy) {
      this.receiptHandleStrategy = receiptHandleStrategy;
      }

    public void handleReceipt(Receipt receipt){
    if (receiptHandleStrategy != null) {
    receiptHandleStrategy.handleReceipt(receipt);
    }
    }
    }`

  • Strategy factory

Copy

`/**

  • @Description: Strategy factory
  • @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

Copy

`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

Copy

`/**

  • @Description: Strategy factory
  • @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

Copy

`/**

  • @Description: abstract receipt processing Interface
  • @Auther: wuzhazha
    */
    public interface IReceiptHandler {

    void handleReceipt(Receipt receipt,IReceiptHandleChain handleChain);

}`

  • Responsibility chain interface

Copy

`/**

  • @Description: Responsibility chain interface
  • @Auther: wuzhazha
    */
    public interface IReceiptHandleChain {

    void handleReceipt(Receipt receipt);
    }`

  • Responsibility chain interface implementation class

Copy

`/**

  • @Description: Chain of Responsibility implementation class
  • @Auther: wuzhazha
    * /
    public class ReceiptHandleChain the implements IReceiptHandleChain {
    // record the current location handlers
    Private int index = 0;
    // set handler
    private static List receiptHandlerList;

    {static
    // Get the object processor from the container
    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

Copy

`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)

Copy

`/**

  • @Description: container handler
  • @Auther: wuzhazha
    */
    public class ReceiptHandlerContainer {

    private ReceiptHandlerContainer(){}

    public static List getReceiptHandlerList(){
    List receiptHandlerList = new ArrayList<>();
    receiptHandlerList.add(new Mt2101ReceiptHandler());
    receiptHandlerList.add(new Mt8104ReceiptHandler());
    return receiptHandlerList;
    }

}`

  • Client

Copy

`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

Copy

`/**

  • @Description: reflection tools
  • @Auther: wuzhazha
    */
    public class ReflectionUtil {

    /**
    • Defined set of classes (for storage of all loaded classes)
      * /
      Private static Final the Set <Class <>> CLASS_SET?;

    {static
    // specified loading package paths
    CLASS_SET = getClassSet ( "com.yaolong");
    }

    /**
    • Get the class loader
    • @return
      */
      public static ClassLoader getClassLoader(){
      return Thread.currentThread().getContextClassLoader();
      }
    /**
    • Load class
    • @param className Fully qualified class name
    • @param isInitialized whether to perform a static block is completed after loading
    • @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);
    }

    /**
    • Get all the classes specified package
    • @param packageName
    • @return
      */
      public static Set<Class<?>> getClassSet(String packageName) {
      Set<Class<?>> classSet = new HashSet<>();
      try {
      Enumeration 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 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;
    }

    /**
    • Get the name of the application package All subclasses of a parent class (or interface) (or implementation class)
    • @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;
      }
    /**
    • Get the application package name with a class annotated
    • @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

Copy

`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

Copy

`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/itplay/p/12090690.html