Instructor: Stefan Mitsch
What if the Receiver of a Command could be one of multiple objects and we do not know a priori which one? What if we want to execute Receiver objects sequentially to do multiple checks on a command?
Receiver
Command
Chain of Responsibility avoids coupling between sender and receiver by allowing multiple request handlers
Problem illustration:
How to avoid inflexible request handling code?
public class RequestHandler { public Response handle(NotificationRequest r) { if (authenticate(r)) { if (authorize(r)) { if (validate(r)) { // ... } else return new InvalidRequestResponse(); } else return new UnauthorizedResponse(); } else return new AuthenticationFailedResponse(); } }
Problem
Allow multiple handlers for a request
Intent
Structure
The Handler declares an common interface for handling requests
Handler
The BaseHandler is optional; if present, it contains fields for storing the next handler and a default implementation to delegate to the next handler
BaseHandler
The ConcreteHandler objects contain the actual code for processing requests (e.g., authentication, authorization, validation); they also know whether to continue processing along the chain
ConcreteHandler
The Client composes chains and may reconfigure them at runtime; it also sends requests to the chain
Client
ConcreteHandlers
// request interface (command pattern) public interface NotificationRequest { String getMessage(); Instant getSchedule(); } // handler interface public interface NotificationRequestHandler { void handle(NotificationRequest r); } // base handler public abstract class BaseNotificationRequestHandler { private NotificationRequestHandler next; public void setNext(NotificationRequestHandler next) { this.next = next; } public Response handle(NotificationRequest r) { if (next != null) return next.handle(r); else return new UnhandledRequestResponse(r); } } // concrete handler public class ValidateNotificationRequest extends BasenNotificationRequestHandler { public Response handle(NotificationRequest r) { if (r.getMessage() != null && !r.getMessage().isEmpty()) super.handle(r); else return new EmptyMessageResponse(); } }