Patterns. The Chain of Responsibility pattern. Java implementation

The Chain of Responsibility pattern. Java implementation example

This topic provides an example of the implementation of the Chain of Responsibility pattern in Java for a structure containing a hierarchy of handler classes. Before exploring the topic, it is recommended that you familiarize yourself with the general information about the Chain of Responsibility pattern, which is described in the topic:


Contents


Search other resources:

1. Task

Let 4 classes ConcreteHandler1, ConcreteHandler2, ConcreteHandler3, ConcreteHandler4 be given. The two classes ConcreteHandler1, ConcreteHandler2 inherit from the Handlers1 class, as shown in Figure 1.

Pattern Chain of Responsibility. The classes hierarchy

Figure 1. The hierarchy of ConcreteHandler1, ConcreteHandler2, Handlers1 classes

It is necessary to develop a Java application in which the above classes handle a single request from the client and are organized in a chain based on the Chain of Responsibility pattern. Demonstrate how the handler classes work by implementing dispatching.

 

2. The solution of task
2.1. Creating the ChainMethod() method

First of all, the ChainMethod() method is introduced into each class, which is the handler itself. This means that this method is processing the client’s request. In our case, the method will display messages about the class name and method name. For example, for the ConcreteHandler1 class, the method will display the message

ConcreteHandler1.ChainMethod

The ChainMethod() method will be passed along the chain to be processed by one of the handler classes.

 

2.2. Building the structure of classes that implement the Chain of Responsibility pattern. Figure

Based on the general structure of the Chain of Responsibility pattern and the input of the ChainMethod() method, the structure shown in Figure 2 is developed.

The structure of the Chain of Responsibility pattern for the classes hierarchy

Figure 2. The structure of the Chain of Responsibility pattern for the classes implemented in the current example

The following steps develop the classes shown in Figure 1.

 

2.3. The Handler class

The base class in the hierarchy is the Handler class. This class creates all the functionality required to implement the Chain of Responsibility pattern. The class declares:

  • internal field successor, which is a reference to the successor. This reference is used in every handler class ConcreteHandler1, ConcreteHandler2, ConcreteHandler3. In the ConcreteHandler4 class, this reference is set to null because this class is the last in the chain of handlers;
  • internal field numHandler, which is the handler number. Based on this number, the DoRequest() method determines whether the request can be handled by a handler;
  • three constructors designed to create an instance of the handler class based on specifying (not specifying) data about the successor and the handler number (numHandler);
  • the ChainMethod() method. This method handles the request directly;
  • the DoRequest() method, which, based on the value of numHandler, determines whether to process the request. If numHandler is -1, then the request is not processed;
  • the SetHandler() method – implements the installation of a handler (successor) and its number (numHandler) after an instance of one of the handler classes is created.

The text of the Handler class is as follows.

// A class that is the only interface for objects that process a request.
// The class contains methods that are common to handle.
class Handler {
  // 1. Internal variables
  // 1.1. Successor reference
  private Handler successor = null;

  // 1.2. Number of the handler processing the request
  private int numHandler = -1;

  // 2. Constructor
  // 2.1. Constructor without a parameters
  public Handler() {
    this(null, -1);
  }

  // 2.2. Constructor with 1 parameter
  public Handler(Handler _successor) {
    this(_successor, -1);
  }

  // 2.3. Constructor with 2 parameters
  public Handler(Handler _successor, int _numHandler) {
    successor = _successor;
    numHandler = _numHandler;
  }

  // A method that moves along a chain.
  // This method processes the request.
  public void ChainMethod() {
    if (successor!=null)
      successor.ChainMethod();
  }

  // A method that determines whether the request should be processed.
  public boolean DoRequest() {
    return numHandler != -1;
  }

  // Method that sets the handler and the ability to handle
  public void SetHandler(Handler _successor, int _numHandler) {
    successor = _successor;
    numHandler = _numHandler;
  }
}

 

2.4. The Handlers1 class

The Handlers1 class is a superclass for the ConcreteHandler1 and ConcreteHandler2 handler classes. For the correct implementation of the Chain of Responsibility pattern, this class must inherit from the Handler class. In the context of our task, the class contains a constructor that calls the constructor of the Handler superclass.

Depending on the problem being solved, besides the constructor, this class may contain other methods and fields.

The Java text for the Handlers1 class is as follows.

// Intermediate class that is the base for specific handlers
// ConcreteHandler1, ConcreteHandler2
class Handlers1 extends Handler {

  // Class constructor
  public Handlers1(Handler _parent, int _numHandler) {
    // Call the base class constructor
    super(_parent, _numHandler);
  }
}

 

2.5. Handler classes ConcreteHandler1, ConcreteHandler2

The classes-handlers ConcreteHandler1, ConcreteHandler2 are inherited from the Handlers1 class. Therefore, the constructors of these classes redirect the inheritor to the constructor of the Handlers1 class. The classes also contain the ChainMethod() method that implements processing.

Additionally, these classes can contain other components that will determine their purpose. The text of the ConcreteHandler1 and ConcreteHandler2 classes is given below.

// Concrete handler - 1
class ConcreteHandler1 extends Handlers1 {

  // Constructor - calls the constructor of the base class Handlers1
  public ConcreteHandler1(Handler _parent, int _numHandler) {
    // Call the constructor of the superclass
    super(_parent, _numHandler);
  }

  // Specific processing method
  public void ChainMethod() {
    // Checking if a handler is processing a given request
    if (super.DoRequest()) {
      // If it does, then take the appropriate action.
      System.out.println("ConcreteHandler1.ChainMethod");
    }
    else {
      super.ChainMethod();
    }
  }
}

// Concrete handler - 2
class ConcreteHandler2 extends Handlers1 {
  public ConcreteHandler2(Handler _parent, int _numHandler) {
    // Call the superclass constructor
    super(_parent, _numHandler);
  }

  // Specific processing method
  public void ChainMethod() {
    // Checking if a handler is processing a given request
    if (super.DoRequest()) {
      // If it does, then take the appropriate action.
      System.out.println("ConcreteHandler2.ChainMethod");
    }
    else {
      super.ChainMethod();
    }
  }
}

 

2.6. The handler class ConcreteHandler3

The ConcreteHandler3 handler class inherits from the base Handler class. This class is not the final link in the call chain.

The class program code is as follows.

// Concrete handler - 3
// This handler is not part of the class hierarchy
// in which the Handlers1 class is the base class.
class ConcreteHandler3 extends Handler {

  // Constructor
  public ConcreteHandler3(Handler _handler, int _numHandler) {
    // Call the superclass constructor
    super(_handler, _numHandler);
  }

  // Specific processing method
  public void ChainMethod() {
    // Checking if a handler is processing a given request
    if (super.DoRequest()) {
      // If it does, then take the appropriate action.
      System.out.println("ConcreteHandler3.ChainMethod");
    }
    else
    {
      super.ChainMethod();
    }
  }
}

 

2.7. The handler class ConcreteHandler4. End of the chain

The ConcreteHandler4 handler class is the last in the chain of calls. Processing in the ChainMethod() method is done accordingly.

The class text is as follows.

// Concrete handler - 4
// This handler is not part of a class hierarchy where
// base class is Handlers1.
// This handler is the last in the chain of handlers.
class ConcreteHandler4 extends Handler {

  // Constructor.
  // Since the handler is the last in the chain of handlers,
  // it does not need to pass a reference to the previous handler.
  public ConcreteHandler4(int _numHandler) {
    super(null, _numHandler);
  }

  // Specific processing method
  public void ChainMethod() {
    // Checking if a handler is processing a given request
    if (super.DoRequest()) {
      // If it does, then take the appropriate action.
      System.out.println("ConcreteHandler4.ChainMethod");
    }
    else
    {
      // If the handler does not process this request,
      // then display a message stating that
      // there is no corresponding handler in the chain.
      System.out.println("There is no corresponding handler in the chain.");
    }
  }
}

 

2.8. Testing the work of the handler classes. Function main(). Dispatching

In this example, the client is the TrainChain class, which contains the main() function – the entry point into the program. In the main() function, the following actions are performed:

  • a chain of handlers is created based on the handler classes described above;
  • a client object is created, pointing to the chain of handler objects;
  • installation and invocation of the appropriate handler based on the simplified dispatch code is demonstrated.

To enter data from the keyboard, the capabilities of the Scanner class are used, which is connected using the directive

import java.util.Scanner;

The client code text is as follows

// Include the Scanner module
import java.util.Scanner;

...

// The client class
public class TrainChain {

  public static void main(String[] args) {
    // Client code.
    // 1. Create a chain of 4 handlers.
    //    Handlers are created in order from last to first.

    // 1.1. The last handler in the chain is created first.
    ConcreteHandler4 handler4 = new ConcreteHandler4(4); // 4 - handler number

    // 1.2. Add next handler.
    //      The handler receives a reference to the previous handler handler4
    ConcreteHandler3 handler3 = new ConcreteHandler3((Handler)handler4, 3);

    // 1.3. Add handlers that are subclasses of the Handlers1 class
    // 1.3.1. The handler that follows the second in the chain.
    ConcreteHandler2 handler2 = new ConcreteHandler2((Handler)handler3, 2);

    // 1.3.2. The first handler in the chain.
    ConcreteHandler1 handler1 = new ConcreteHandler1((Handler)handler2, 1);

    // 2. Create a client.
    //    Client points to a chain of handler objects
    //    client -> handler1 -> handler2 -> handler3 -> handler4
    Handler client = new Handler((Handler)handler1);

    // 3. Enter the handler number from the keyboard
    System.out.println("numHandler = ");
    Scanner input = new Scanner(System.in);
    int numHandler = input.nextInt();

    // 4. Depending on numObject implement dispatching
    switch (numHandler) {
      case 1:
        // Set handler-1 for client and call it
        client.SetHandler(handler1, 1);
        client.ChainMethod();
        break;
      case 2:
        // Set handler-2 for client and call it
        client.SetHandler(handler2, 2);
        client.ChainMethod();
        break;
      case 3:
        // Set handler-3 for client and call it
        client.SetHandler(handler3, 3);
        client.ChainMethod();
        break;
      case 4:
        // Set handler-4 for client and call it
        client.SetHandler(handler4, 4);
        client.ChainMethod();
        break;
      default:
        System.out.println("Incorrect handler");
        break;
    }

    // Close the input stream
    input.close();
  }
}

 

2.9. Abbreviated program structure

To get the entire program code, you need to copy the program codes presented in paragraphs 2.1-2.5 of this topic. In an abbreviated form, the structure of the program is as follows:

// Include the Scanner module
import java.util.Scanner;

// A class that is the only interface for objects that process a request
class Handler {
  ...
}

// Intermediate class that is the base for specific handlers
// ConcreteHandler1, ConcreteHandler2
class Handlers1 extends Handler {
  ...
}

// Concrete handler - 1
class ConcreteHandler1 extends Handlers1 {
  ...
}

// Concrete handler - 2
class ConcreteHandler2 extends Handlers1 {
  ...
}

// Concrete handler - 3
class ConcreteHandler3 extends Handler {
  ...
}

// Concrete handler - 4
class ConcreteHandler4 extends Handler {
  ...
}

// Client class
public class TrainChain {
  public static void main(String[] args) {
    ...
  }
}

 


Related topics