Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Chain of responsibility pattern


May 27, 2021 Design mode


Table of contents


Chain of responsibility pattern

As the name implies, Chain of Responsibility Pattern creates a chain of recipient objects for requests. T his pattern gives the type of request, decoupling the sender and recipient of the request. This type of design pattern is behavioral.

In this pattern, usually each recipient contains a reference to another recipient. If an object cannot process the request, it sends the same request to the next recipient, and so on.

Introduced

Intent: Avoid the request sender coupling with the recipient, making it possible for multiple objects to receive requests, connecting them into a chain, and passing requests along that chain until an object processes it.

Primary Solution: The handler on the chain of responsibilities handles the request, and the customer only needs to send the request to the chain of responsibility, regardless of the details of the request's processing and the delivery of the request, so the chain of responsibility decouples the sender of the request and the handler of the request.

When to use: Filters many lanes when processing messages.

How to solve: Intercepted classes implement a unified interface.

Key code: Handler aggregates itself inside, determines whether it is appropriate in HanleRequest, passes down if the condition is not met, and passes it to whom before the set goes in.

Application example: 1, the dream of the red building "drumming flowers." 2 , events in JS bubble. 3 , APache Tomcat's handling of Encoding in JAVA WEB, Struts2's interceptor, jsp servlet's Filter.

Pros: 1, reduce coupling. I t decouples the sender and receiver of the request. 2 , simplified the object. S o that the object does not need to know the structure of the chain. 3 , enhance the flexibility of assigning responsibilities to objects. A llows responsibilities to be added or removed dynamically by changing the order of members within the chain or by mobilizing them. 4 , adding a new request processing class is convenient.

Cons: 1, there is no guarantee that the request will be received. 2 , the performance of the system will be affected, and in the code debugging is not convenient, may cause circular calls. 3 , may not be easy to observe the characteristics of the runtime, hinder the removal of errors.

Scenario: 1, there are multiple objects that can handle the same request, and which object handles the request is automatically determined by the run time. 2 . Submit a request to one of multiple objects without explicitly specifying the recipient. 3 , you can dynamically specify a set of objects to handle requests.

Note: Many applications are encountered in JAVA WEB.

Realize

We create an abstract class, AbstractLogger, with a detailed level of logging. T hen we created three types of loggers, all of which extended AbstractLogger. Whether the level of each logger message belongs to its own level, or if so, prints it accordingly, otherwise the message will not be printed and passed to the next logger.

Chain of responsibility pattern

Step 1

Create an abstract recorder class.

AbstractLogger.java

public abstract class AbstractLogger {
   public static int INFO = 1;
   public static int DEBUG = 2;
   public static int ERROR = 3;

   protected int level;

   //责任链中的下一个元素
   protected AbstractLogger nextLogger;

   public void setNextLogger(AbstractLogger nextLogger){
      this.nextLogger = nextLogger;
   }

   public void logMessage(int level, String message){
      if(this.level <= level){          write(message);       }       if(nextLogger !=null){          nextLogger.logMessage(level, message);       }    }     abstract protected void write(String message);    } 

Step 2

Create an entity class that extends the logger class.

ConsoleLogger.java

public class ConsoleLogger extends AbstractLogger {

   public ConsoleLogger(int level){
      this.level = level;
   }

   @Override
   protected void write(String message) {     
      System.out.println("Standard Console::Logger: " + message);
   }
}

ErrorLogger.java

public class ErrorLogger extends AbstractLogger {

   public ErrorLogger(int level){
      this.level = level;
   }

   @Override
   protected void write(String message) {       
      System.out.println("Error Console::Logger: " + message);
   }
}

FileLogger.java

public class FileLogger extends AbstractLogger {

   public FileLogger(int level){
      this.level = level;
   }

   @Override
   protected void write(String message) {     
      System.out.println("File::Logger: " + message);
   }
}

Step 3

Create different types of loggers. G ive them different error levels and set the next recorder in each logger. The next logger in each logger represents a part of the chain.

ChainPatternDemo.java

public class ChainPatternDemo {
  
   private static AbstractLogger getChainOfLoggers(){

      AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
      AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
      AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);

      errorLogger.setNextLogger(fileLogger);
      fileLogger.setNextLogger(consoleLogger);

      return errorLogger;    
   }

   public static void main(String[] args) {
      AbstractLogger loggerChain = getChainOfLoggers();

      loggerChain.logMessage(AbstractLogger.INFO, 
         "This is an information.");

      loggerChain.logMessage(AbstractLogger.DEBUG, 
         "This is an debug level information.");

      loggerChain.logMessage(AbstractLogger.ERROR, 
         "This is an error information.");
   }
}

Step 4

Verify the output.

Standard Console::Logger: This is an information.
File::Logger: This is an debug level information.
Standard Console::Logger: This is an debug level information.
Error Console::Logger: This is an error information.
File::Logger: This is an error information.
Standard Console::Logger: This is an error information.