zoukankan      html  css  js  c++  java
  • Chain Of Responsibility Design Pattern Example

    Avoid coupling the sender of a request to the receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

    The main intention in Chain Of Responsibility is to decouple the origin of the request and the handling of the request such that the origin of the request need not worry who and how its request is being handled as long as it gets the expected outcome. By decoupling the origin of the request and the request handler we make sure that both can change easily and new request handlers can be added without the origin of the request i.e client being aware of the changes. In this pattern we create a chain of objects such that each object will have a reference to another object which we call it as successor and these objects are responsible for handling the request from the client. All the objects which are part of the chain are created from classes which confirm to a common interface there by the client only needs to be aware of the interface and not necessarily the types of its implementations. The client assigns the request to first object part of the chain and the chain is created in such a way that there would be atleast one object which can handle the request or the client would be made aware of the fact that its request couldn’t be handled.

    With this brief introduction I would like to put forth a very simple example to illustrate this pattern. In this example we create a chain of file parsers such that depending on the format of the file being passed to the parser, the parser has to decide whether its going to parse the file or pass the request to its successor parser to take action. The parser we would chain are: Simple text file parser, JSON file parser, CSV file parser and XML file parser. The parsing logic in each of these parser doesn’t parse any file, instead it just prints out a message stating who is handing the request for which file. We then populate file names of different formats into a list and then iterate through them passing the file name to the first parser in the list.

    Lets define the Parser class, first let me show the class diagram for Parser class:

    The Java code for the same is:

    01 public class Parser {
    02    
    03   private Parser successor;
    04    
    05   public void parse(String fileName){
    06     if ( getSuccessor() != null ){
    07       getSuccessor().parse(fileName);
    08     }
    09     else{
    10       System.out.println('Unable to find the correct parser for the file: '+fileName);
    11     }
    12   }
    13    
    14   protected boolean canHandleFile(String fileName, String format){
    15     return (fileName == null) || (fileName.endsWith(format));
    16          
    17   }
    18  
    19   Parser getSuccessor() {
    20     return successor;
    21   }
    22  
    23   void setSuccessor(Parser successor) {
    24     this.successor = successor;
    25   }
    26 }

    We would now create different handlers for parsing different file formats namely- Simple text file, JSON file, CSV file, XML file and these extend from the Parser class and override the parse method. I have kept the implementation of different parser simple and these methods evaluate if the file has the format they are looking for. If a particular handler is unable to process the request i.e. the file format is not what it is looking for then the parent method handles such requests. The handler method in the parent class just invokes the same method on the successor handler.

    The simple text parser:

    01 public class TextParser extends Parser{
    02  
    03   public TextParser(Parser successor){
    04     this.setSuccessor(successor);
    05   }
    06    
    07   @Override
    08   public void parse(String fileName) {
    09     if ( canHandleFile(fileName, '.txt')){
    10       System.out.println('A text parser is handling the file: '+fileName);
    11     }
    12     else{
    13       super.parse(fileName);
    14     }
    15      
    16   }
    17  
    18 }

    The JSON parser:

    01 public class JsonParser extends Parser {
    02  
    03   public JsonParser(Parser successor){
    04     this.setSuccessor(successor);
    05   }
    06    
    07   @Override
    08   public void parse(String fileName) {
    09     if ( canHandleFile(fileName, '.json')){
    10       System.out.println('A JSON parser is handling the file: '+fileName);
    11     }
    12     else{
    13       super.parse(fileName);
    14     }
    15  
    16   }
    17  
    18 }

    The CSV parser:

    01 public class CsvParser extends Parser {
    02  
    03   public CsvParser(Parser successor){
    04     this.setSuccessor(successor);
    05   }
    06    
    07   @Override
    08   public void parse(String fileName) {
    09     if ( canHandleFile(fileName, '.csv')){
    10       System.out.println('A CSV parser is handling the file: '+fileName);
    11     }
    12     else{
    13       super.parse(fileName);
    14     }
    15   }
    16  
    17 }

    The XML parser:

    01 public class XmlParser extends Parser {
    02    
    03   @Override
    04   public void parse(String fileName) {
    05     if ( canHandleFile(fileName, '.xml')){
    06       System.out.println('A XML parser is handling the file: '+fileName);
    07     }
    08     else{
    09       super.parse(fileName);
    10     }
    11   }
    12  
    13 }

    Now that we have all the handlers setup, we need to create a chain of handlers. In this example the chain we create is: TextParser -> JsonParser -> CsvParser -> XmlParser. And if XmlParser is unable to handle the request then the Parser class throws out a message stating that the request was not handled. Lets see the code for the client class which creates a list of files names and then creates the chain which I just described.

    01 import java.util.List;
    02 import java.util.ArrayList;
    03  
    04 public class ChainOfResponsibilityDemo {
    05  
    06   /**
    07    * @param args
    08    */
    09   public static void main(String[] args) {
    10      
    11     //List of file names to parse.
    12     List<String> fileList = populateFiles();
    13      
    14     //No successor for this handler because this is the last in chain.
    15     Parser xmlParser = new XmlParser();
    16  
    17     //XmlParser is the successor of CsvParser.
    18     Parser csvParser = new CsvParser(xmlParser);
    19      
    20     //CsvParser is the successor of JsonParser.
    21     Parser jsonParser = new JsonParser(csvParser);
    22      
    23     //JsonParser is the successor of TextParser.
    24     //TextParser is the start of the chain.
    25     Parser textParser = new TextParser(jsonParser);
    26      
    27     //Pass the file name to the first handler in the chain.
    28     for ( String fileName : fileList){
    29       textParser.parse(fileName);
    30     }
    31  
    32   }
    33    
    34   private static List<String> populateFiles(){
    35      
    36     List<String> fileList = new ArrayList<>();
    37     fileList.add('someFile.txt');
    38     fileList.add('otherFile.json');
    39     fileList.add('xmlFile.xml');
    40     fileList.add('csvFile.csv');
    41     fileList.add('csvFile.doc');
    42      
    43     return fileList;
    44   }
    45  
    46 }

    In the file name list above I have intentionally added a file name for which there is no handler created. Running the above code gives us the output:

    1 A text parser is handling the file: someFile.txt
    2 A JSON parser is handling the file: otherFile.json
    3 A XML parser is handling the file: xmlFile.xml
    4 A CSV parser is handling the file: csvFile.csv
    5 Unable to find the correct parser for the file: csvFile.doc

    Happy coding and don’t forget to share!

    Reference: Simple example to illustrate Chain Of Responsibility Design Pattern from our JCG partner Mohamed Sanaulla at the Experiences Unlimited blog.

  • 相关阅读:
    Ceres-Solver学习日志:手动求导使用样例与cvLMSolver使用对比
    Ceres-Solver学习日志:自动求导使用样例与针孔成像器的应用
    Ceres-Solver学习日志:官方典型使用样例与Ceres使用要点
    OpenCV-Core学习日志:数学基础函数实验
    OpenCV-Core学习日志:Mat要点总结
    OpenCV-Utils学习日志:viz模块要点总结
    OpenCV-Utils学习日志:GUI模块要点总结
    C++拷贝构造函数剖析(copy constructor)
    Linux下实现mysleep并分析
    输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
  • 原文地址:https://www.cnblogs.com/chenying99/p/3600926.html
Copyright © 2011-2022 走看看