Browse Java Design Patterns & Enterprise Application Architecture

Dynamic vs. Static Chain Construction in Java

Compare fixed and runtime-built Java handler chains so you can choose between predictability, configurability, and operational complexity.

8.2.2 Dynamic vs. Static Chains

The Chain of Responsibility pattern is a behavioral design pattern that allows an object to pass a request along a chain of potential handlers until one of them handles the request. This pattern decouples the sender and receiver of a request, providing flexibility in assigning responsibilities to objects. In this section, we delve into the nuances of dynamic and static chains within the Chain of Responsibility pattern, exploring their implementations, advantages, and appropriate use cases.

Static Chains

Definition

Static chains in the Chain of Responsibility pattern are defined at compile-time. This means that the sequence of handlers is predetermined and cannot be altered during runtime. Each handler in the chain is explicitly linked to the next, forming a fixed sequence of responsibility.

Implementation

In a static chain, the handlers are typically instantiated and linked together in a specific order within the code. This approach is straightforward and ensures a predictable flow of request handling.

 1// Define an abstract handler class
 2abstract class Handler {
 3    protected Handler nextHandler;
 4
 5    public void setNextHandler(Handler nextHandler) {
 6        this.nextHandler = nextHandler;
 7    }
 8
 9    public abstract void handleRequest(String request);
10}
11
12// Concrete handler classes
13class ConcreteHandlerA extends Handler {
14    @Override
15    public void handleRequest(String request) {
16        if (request.equals("A")) {
17            System.out.println("ConcreteHandlerA handled the request.");
18        } else if (nextHandler != null) {
19            nextHandler.handleRequest(request);
20        }
21    }
22}
23
24class ConcreteHandlerB extends Handler {
25    @Override
26    public void handleRequest(String request) {
27        if (request.equals("B")) {
28            System.out.println("ConcreteHandlerB handled the request.");
29        } else if (nextHandler != null) {
30            nextHandler.handleRequest(request);
31        }
32    }
33}
34
35// Client code
36public class StaticChainDemo {
37    public static void main(String[] args) {
38        Handler handlerA = new ConcreteHandlerA();
39        Handler handlerB = new ConcreteHandlerB();
40
41        handlerA.setNextHandler(handlerB);
42
43        handlerA.handleRequest("A");
44        handlerA.handleRequest("B");
45        handlerA.handleRequest("C");
46    }
47}

In this example, ConcreteHandlerA and ConcreteHandlerB are linked in a static sequence. The request is passed along the chain until a handler processes it or the chain ends.

Advantages and Disadvantages

  • Advantages:

    • Predictability: The sequence of handlers is known at compile-time, making the system behavior predictable.
    • Simplicity: Implementation is straightforward with minimal runtime overhead.
  • Disadvantages:

    • Inflexibility: The chain cannot adapt to changing conditions or requirements at runtime.
    • Maintenance: Modifying the chain requires code changes and recompilation.

Dynamic Chains

Definition

Dynamic chains allow the sequence of handlers to be modified at runtime. This flexibility enables the system to adapt to varying conditions or requirements without altering the codebase.

Implementation

Dynamic chains are typically implemented using collections or data structures that can be manipulated at runtime. This approach allows handlers to be added, removed, or reordered as needed.

 1import java.util.ArrayList;
 2import java.util.List;
 3
 4// Define an interface for handlers
 5interface DynamicHandler {
 6    void handleRequest(String request);
 7}
 8
 9// Concrete handler classes
10class DynamicHandlerA implements DynamicHandler {
11    @Override
12    public void handleRequest(String request) {
13        if (request.equals("A")) {
14            System.out.println("DynamicHandlerA handled the request.");
15        }
16    }
17}
18
19class DynamicHandlerB implements DynamicHandler {
20    @Override
21    public void handleRequest(String request) {
22        if (request.equals("B")) {
23            System.out.println("DynamicHandlerB handled the request.");
24        }
25    }
26}
27
28// Client code
29public class DynamicChainDemo {
30    private List<DynamicHandler> handlers = new ArrayList<>();
31
32    public void addHandler(DynamicHandler handler) {
33        handlers.add(handler);
34    }
35
36    public void handleRequest(String request) {
37        for (DynamicHandler handler : handlers) {
38            handler.handleRequest(request);
39        }
40    }
41
42    public static void main(String[] args) {
43        DynamicChainDemo chain = new DynamicChainDemo();
44        chain.addHandler(new DynamicHandlerA());
45        chain.addHandler(new DynamicHandlerB());
46
47        chain.handleRequest("A");
48        chain.handleRequest("B");
49        chain.handleRequest("C");
50    }
51}

In this example, handlers are stored in a list, allowing the chain to be modified dynamically. The client can add or remove handlers as needed, providing flexibility in request processing.

Advantages and Disadvantages

  • Advantages:

    • Flexibility: The chain can be adjusted at runtime to accommodate changing requirements or conditions.
    • Adaptability: New handlers can be introduced without modifying existing code.
  • Disadvantages:

    • Complexity: Managing dynamic chains can introduce additional complexity in terms of state management and synchronization.
    • Performance: Dynamic modifications may incur runtime overhead.

Flexibility of Dynamic Chains

Dynamic chains offer significant flexibility, making them suitable for scenarios where the sequence of handlers may change based on runtime conditions. For example, in a web application, different request handlers might be activated based on user roles or preferences. Dynamic chains enable the system to adapt without requiring code changes or redeployment.

Real-World Scenario

Consider a logging system where different log levels (INFO, DEBUG, ERROR) require different handling strategies. A dynamic chain can adjust the sequence of handlers based on the current log level, ensuring that only relevant handlers process the log messages.

 1// Define a logging handler interface
 2interface LogHandler {
 3    void log(String message);
 4}
 5
 6// Concrete log handler classes
 7class InfoLogHandler implements LogHandler {
 8    @Override
 9    public void log(String message) {
10        System.out.println("INFO: " + message);
11    }
12}
13
14class ErrorLogHandler implements LogHandler {
15    @Override
16    public void log(String message) {
17        System.out.println("ERROR: " + message);
18    }
19}
20
21// Client code
22public class LoggingSystem {
23    private List<LogHandler> logHandlers = new ArrayList<>();
24
25    public void addLogHandler(LogHandler handler) {
26        logHandlers.add(handler);
27    }
28
29    public void logMessage(String message) {
30        for (LogHandler handler : logHandlers) {
31            handler.log(message);
32        }
33    }
34
35    public static void main(String[] args) {
36        LoggingSystem loggingSystem = new LoggingSystem();
37        loggingSystem.addLogHandler(new InfoLogHandler());
38        loggingSystem.addLogHandler(new ErrorLogHandler());
39
40        loggingSystem.logMessage("This is an informational message.");
41        loggingSystem.logMessage("This is an error message.");
42    }
43}

In this logging system, handlers can be added or removed based on the desired log level, providing a flexible and adaptable solution.

Choosing Between Static and Dynamic Chains

The choice between static and dynamic chains depends on the specific requirements and constraints of the application. Consider the following factors when deciding which approach to use:

  • Predictability vs. Flexibility: If the sequence of handlers is unlikely to change and predictability is crucial, a static chain may be more appropriate. Conversely, if flexibility and adaptability are required, a dynamic chain is preferable.

  • Performance Considerations: Static chains generally offer better performance due to their simplicity and lack of runtime modifications. Dynamic chains may introduce overhead but provide greater adaptability.

  • Maintenance and Scalability: Static chains are easier to maintain in stable environments, while dynamic chains offer scalability and ease of modification in evolving systems.

Conclusion

Understanding the differences between dynamic and static chains in the Chain of Responsibility pattern is essential for designing flexible and efficient systems. By carefully evaluating the needs of your application, you can choose the most suitable approach to implement this pattern effectively. Experiment with both static and dynamic chains in your projects to gain a deeper understanding of their advantages and limitations.

Exercises

  1. Modify the static chain example to include a third handler and test its behavior.
  2. Implement a dynamic chain that adjusts the sequence of handlers based on user input.
  3. Compare the performance of static and dynamic chains in a high-load scenario.

Key Takeaways

  • Static chains offer predictability and simplicity but lack flexibility.
  • Dynamic chains provide adaptability and scalability at the cost of increased complexity.
  • The choice between static and dynamic chains should be guided by the application’s requirements and constraints.

References and Further Reading

Test Your Knowledge: Dynamic vs. Static Chains in Java Design Patterns

Loading quiz…

Revised on Thursday, April 23, 2026