Chain of Responsibility and Mediator Patterns

Site Admin · 11 Sep 2026 · 10 views

Chain of Responsibility and Mediator Patterns

The Chain of Responsibility pattern lets you pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. The Mediator pattern reduces chaotic dependencies between objects by restricting direct communications and forcing them to collaborate via a mediator object.

Both patterns aim to reduce coupling, but they solve different problems. Chain of Responsibility decouples the sender from the receiver. Mediator decouples a set of objects from each other.

Chain of Responsibility

Instead of coupling a sender to a specific receiver, you give multiple objects a chance to handle the request. Each handler has a reference to the next handler and either handles the request or forwards it.

+-------------------+
|  Authorization    |
|     Request       |
+--------+----------+
         |
         v
+-------------------+     +-------------------+
| RoleCheckHandler  |---->| RightsCheckHandler|
| next -> next      |     | next -> next      |
+-------------------+     +-------------------+
                                    |
                                    v
                          +-------------------+
                          | AuditLogHandler   |
                          | next -> null      |
                          +-------------------+

Each handler either handles the request or passes it along. The chain can be reordered, extended, or trimmed without changing any handler code.

Handler Implementation

Every handler extends an abstract base that holds the next handler reference and a template method.

public abstract class Handler {
    protected Handler next;

    public Handler setNext(Handler next) {
        this.next = next;
        return next;
    }

    public void handle(Request request) {
        if (canHandle(request)) {
            process(request);
        } else if (next != null) {
            next.handle(request);
        }
    }

    protected abstract boolean canHandle(Request request);
    protected abstract void process(Request request);
}

The setNext method returns the passed handler so you can chain calls fluently. The handle method checks canHandle and either processes or forwards the request.

Concrete Handlers

Each handler specialises in one aspect of processing.

public class AuthenticationHandler extends Handler {
    protected boolean canHandle(Request request) {
        return !request.isAuthenticated();
    }
    protected void process(Request request) {
        System.out.println("Authenticating user...");
        request.setAuthenticated(true);
    }
}

public class RateLimitHandler extends Handler {
    protected boolean canHandle(Request request) {
        return request.getCount() > 100;
    }
    protected void process(Request request) {
        System.out.println("Rate limit exceeded. Rejecting.");
    }
}

AuthenticationHandler fires only when the user is not yet authenticated. RateLimitHandler fires only when the request count exceeds the threshold. Each handler is independent and testable in isolation.

Mediator Pattern

In a chat room, every user could broadcast to every other user directly - creating N times N connections. A chat room mediator sits in the middle. Users send messages to the mediator, and the mediator forwards them to all other users.

+-----------+        +---------------+        +-----------+
| UserAlice | ---->  | ChatRoom      | ---->  | UserBob   |
+-----------+        | (mediator)    |        +-----------+
                     +---------------+
                          ^     ^
                     +----+     +----+
                     |              |
               +---------+    +--------+
               | UserCarol|   | UserDan |
               +---------+    +--------+

Each user only knows about the mediator, not about other users. The mediator controls the interaction logic.

public interface ChatMediator {
    void sendMessage(String message, User sender);
    void addUser(User user);
}

public class ChatRoom implements ChatMediator {
    private List<User> users = new ArrayList<>();

    public void addUser(User user) {
        users.add(user);
    }

    public void sendMessage(String message, User sender) {
        for (User user : users) {
            if (user != sender) {
                user.receive(message);
            }
        }
    }
}

The ChatRoom iterates over all registered users and forwards the message to everyone except the sender. Users do not hold references to each other.

Real-World Scenario

A web request pipeline combines both patterns. Servlet filters form a Chain of Responsibility - each filter performs one task such as authentication, logging, or compression and either completes the request or passes it to the next filter. At the application level, a UI form with many interdependent fields uses a Mediator to coordinate changes. When the user selects a country, the mediator tells the city dropdown to reload its options without the two dropdowns knowing about each other.

Key Points

  • Chain of Responsibility passes requests along a chain, decoupling senders from specific receivers.
  • Each handler in the chain decides independently whether to process or forward the request.
  • The Mediator centralises complex communications between a set of objects into one object.
  • Mediators prevent tight coupling but can become complex themselves if the interaction logic grows.
  • Both patterns reduce dependencies: Chain of Responsibility along a linear path, Mediator in a hub-and-spoke topology.
Share this post:

Comments (0)

Please login or register to comment.