|
| 1 | +--- |
| 2 | +tags: |
| 3 | + - behavioral |
| 4 | +created: 2026-04-02 |
| 5 | +title: Chain Of Responsibility Pattern |
| 6 | +--- |
| 7 | +## Definition |
| 8 | + |
| 9 | +**Chain of Responsibility Pattern** is the Behavioral design pattern that let you pass request along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain. |
| 10 | + |
| 11 | +--- |
| 12 | +## Real World Analogy |
| 13 | + |
| 14 | +Think of a login system in an application. When a user tries to log in, multiple checks need to happen in a specific order. First, the system verifies whether the user exists. If the user is valid, it then checks the password. After that, it verifies the role or permissions of the user. |
| 15 | + |
| 16 | +Now, not every request always needs all checks. Some parts of the system may only require user verification, while others may also need role validation. Instead of writing all these checks in one place with complex conditions, we can split them into separate handlers and connect them in a chain. |
| 17 | + |
| 18 | +Each handler performs its own responsibility and then passes the request to the next handler only if the current check is successful. If any check fails, the process stops immediately. This makes the system flexible and easy to modify. |
| 19 | + |
| 20 | +--- |
| 21 | +## Design |
| 22 | + |
| 23 | +```mermaid |
| 24 | +classDiagram |
| 25 | +
|
| 26 | +%% Interface |
| 27 | +class Handle { |
| 28 | + <<interface>> |
| 29 | + +setNext(handler: Handle) |
| 30 | + +handle(requester: User) |
| 31 | +} |
| 32 | +
|
| 33 | +%% Abstract Class |
| 34 | +class BaseHandler { |
| 35 | + -next: Handle |
| 36 | + +setNext(handler: Handle) |
| 37 | + +handle(requester: User) |
| 38 | +} |
| 39 | +
|
| 40 | +%% Concrete Handlers |
| 41 | +class UserCheckHandler { |
| 42 | + +handle(requester: User) |
| 43 | +} |
| 44 | +
|
| 45 | +class PasswordCheckHandler { |
| 46 | + +handle(requester: User) |
| 47 | +} |
| 48 | +
|
| 49 | +class RoleCheckHandler { |
| 50 | + +handle(requester: User) |
| 51 | +} |
| 52 | +
|
| 53 | +%% Builder |
| 54 | +class AuthBuilder { |
| 55 | + +buildChain(): Handle |
| 56 | +} |
| 57 | +
|
| 58 | +%% Relationships |
| 59 | +Handle <|.. BaseHandler |
| 60 | +BaseHandler <|-- UserCheckHandler |
| 61 | +BaseHandler <|-- PasswordCheckHandler |
| 62 | +BaseHandler <|-- RoleCheckHandler |
| 63 | +
|
| 64 | +BaseHandler --> Handle : next |
| 65 | +AuthBuilder --> Handle : builds chain |
| 66 | +``` |
| 67 | + |
| 68 | +_Class Diagram for Authentication using Chain of Responsibility Pattern_ |
| 69 | + |
| 70 | +--- |
| 71 | +## Implementation in Java |
| 72 | + |
| 73 | +```java title="User.java" |
| 74 | +class User { |
| 75 | + String username; |
| 76 | + String role; |
| 77 | + String password; |
| 78 | + |
| 79 | + public User(String username, String password, String role) { |
| 80 | + this.username = username; |
| 81 | + this.password = password; |
| 82 | + this.role = role; |
| 83 | + } |
| 84 | + |
| 85 | + public String getUsername() { |
| 86 | + return username; |
| 87 | + } |
| 88 | + |
| 89 | + public String getRole() { |
| 90 | + return role; |
| 91 | + } |
| 92 | + |
| 93 | + public String getPassword() { |
| 94 | + return password; |
| 95 | + } |
| 96 | +} |
| 97 | +``` |
| 98 | +This class represents the user object that contains username, password, and role. It acts as the request that will be passed through the chain of handlers. |
| 99 | + |
| 100 | +```java title="Handle.java" |
| 101 | +// Handler Interface |
| 102 | +interface Handle { |
| 103 | + void setNext(Handle handler); |
| 104 | + |
| 105 | + void handle(User requester); |
| 106 | +} |
| 107 | +``` |
| 108 | +This interface defines the structure for all handlers. Each handler must be able to set the next handler and process the request. |
| 109 | + |
| 110 | +```java title="BaseHandler.java" |
| 111 | +abstract class BaseHandler implements Handle { |
| 112 | + protected Handle next; |
| 113 | + |
| 114 | + @Override |
| 115 | + public void setNext(Handle handler) { |
| 116 | + this.next = handler; |
| 117 | + } |
| 118 | + |
| 119 | + @Override |
| 120 | + public void handle(User requester) { |
| 121 | + if (next != null) { |
| 122 | + next.handle(requester); |
| 123 | + } |
| 124 | + } |
| 125 | +} |
| 126 | +``` |
| 127 | +This abstract class provides a common implementation for all handlers. It stores the reference of the next handler and forwards the request when needed. Concrete handlers will extend this class and add their own logic. |
| 128 | + |
| 129 | +```java title="UserCheckHandler.java" |
| 130 | +class UserCheckHandler extends BaseHandler { |
| 131 | + @Override |
| 132 | + public void handle(User requester) { |
| 133 | + if (!requester.getUsername().equals("admin")) { |
| 134 | + System.out.println("User Does not Exists"); |
| 135 | + return; |
| 136 | + } |
| 137 | + System.out.println("User Verified"); |
| 138 | + super.handle(requester); |
| 139 | + } |
| 140 | +} |
| 141 | +``` |
| 142 | +This handler checks whether the username is valid. If the user does not exist, the chain stops here. If the check passes, it forwards the request to the next handler. |
| 143 | + |
| 144 | +```java title="PasswordCheckHandler.java" |
| 145 | +class PasswordCheckHandler extends BaseHandler { |
| 146 | + @Override |
| 147 | + public void handle(User requester) { |
| 148 | + if (!requester.getPassword().equals("1234")) { |
| 149 | + System.out.println("Invalid password"); |
| 150 | + return; |
| 151 | + } |
| 152 | + |
| 153 | + System.out.println("Password verified"); |
| 154 | + super.handle(requester); |
| 155 | + } |
| 156 | +} |
| 157 | +``` |
| 158 | +This handler validates the password. If the password is incorrect, the process stops. Otherwise, it passes the request further. |
| 159 | + |
| 160 | +```java title="RoleCheckHandler.java" |
| 161 | +class RoleCheckHandler extends BaseHandler { |
| 162 | + |
| 163 | + @Override |
| 164 | + public void handle(User requester) { |
| 165 | + if (!requester.getRole().equals("ADMIN")) { |
| 166 | + System.out.println("Access denied: insufficient role"); |
| 167 | + return; |
| 168 | + } |
| 169 | + |
| 170 | + System.out.println("Role verified → Access granted!"); |
| 171 | + super.handle(requester); |
| 172 | + } |
| 173 | +} |
| 174 | +``` |
| 175 | +This handler checks whether the user has the required role. If not, access is denied. If the role is valid, the request successfully completes. |
| 176 | + |
| 177 | +```java title="AuthBuilder.java" |
| 178 | +class AuthBuilder { |
| 179 | + public static Handle buildChain() { |
| 180 | + Handle usercheck = new UserCheckHandler(); |
| 181 | + Handle passwordcheck = new PasswordCheckHandler(); |
| 182 | + Handle rolecheck = new RoleCheckHandler(); |
| 183 | + |
| 184 | + usercheck.setNext(passwordcheck); |
| 185 | + passwordcheck.setNext(rolecheck); |
| 186 | + return usercheck; |
| 187 | + } |
| 188 | +} |
| 189 | +``` |
| 190 | +This class is responsible for building the chain. It creates each handler and connects them in the required order. |
| 191 | + |
| 192 | +```java title="CORPattern.java" |
| 193 | +public static void main(String[] args) { |
| 194 | + User user = new User("admin", "1234", "ADMIN"); |
| 195 | + |
| 196 | + Handle chain = AuthBuilder.buildChain(); |
| 197 | + chain.handle(user); |
| 198 | + |
| 199 | + System.out.println(); |
| 200 | + User user1 = new User("admin", "12234", "ADMIN"); |
| 201 | + chain.handle(user1); |
| 202 | +} |
| 203 | +``` |
| 204 | +Here we create users and pass them through the chain. The chain processes each request step by step based on the defined handlers. |
| 205 | + |
| 206 | +**Output**: |
| 207 | +```bash |
| 208 | +User Verified |
| 209 | +Password verified |
| 210 | +Role verified → Access granted! |
| 211 | + |
| 212 | +User Verified |
| 213 | +Invalid password |
| 214 | +``` |
| 215 | + |
| 216 | +--- |
| 217 | +## Real World Example |
| 218 | + |
| 219 | +This pattern is commonly used in middleware pipelines such as Spring and .NET Core. In these systems, a request passes through multiple middleware components, where each component performs a specific task like authentication, logging, or validation before passing it to the next component. |
| 220 | + |
| 221 | +It is also used in logging frameworks. A log request can pass through different handlers based on its level, such as info, debug, or error, and then get written to different outputs like files or console. |
| 222 | + |
| 223 | +This approach keeps the system clean, flexible, and easy to extend. |
| 224 | + |
| 225 | +--- |
| 226 | +## Design Principles: |
| 227 | + |
| 228 | +- **Encapsulate What Varies** - Identify the parts of the code that are going to change and encapsulate them into separate class just like the Strategy Pattern. |
| 229 | +- **Favor Composition Over Inheritance** - Instead of using inheritance on extending functionality, rather use composition by delegating behavior to other objects. |
| 230 | +- **Program to Interface not Implementations** - Write code that depends on Abstractions or Interfaces rather than Concrete Classes. |
| 231 | +- **Strive for Loosely coupled design between objects that interact** - When implementing a class, avoid tightly coupled classes. Instead, use loosely coupled objects by leveraging abstractions and interfaces. This approach ensures that the class does not heavily depend on other classes. |
| 232 | +- **Classes Should be Open for Extension But closed for Modification** - Design your classes so you can extend their behavior without altering their existing, stable code. |
| 233 | +- **Depend on Abstractions, Do not depend on concrete class** - Rely on interfaces or abstract types instead of concrete classes so you can swap implementations without altering client code. |
| 234 | +- **Talk Only To Your Friends** - An object may only call methods on itself, its direct components, parameters passed in, or objects it creates. |
| 235 | +- **Don't call us, we'll call you** - This means the framework controls the flow of execution, not the user’s code (Inversion of Control). |
| 236 | +- **A class should have only one reason to change** - This emphasizes the Single Responsibility Principle, ensuring each class focuses on just one functionality. |
0 commit comments