-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchain_of_responsibility.cpp
More file actions
167 lines (138 loc) · 5 KB
/
chain_of_responsibility.cpp
File metadata and controls
167 lines (138 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <iostream>
#include <memory>
using namespace std;
/*
==============================================================
🧩 Design Pattern: Chain of Responsibility (CoR)
==============================================================
📘 Definition:
---------------
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.
This pattern helps decouple the sender of a request from its receivers,
allowing multiple objects a chance to handle that request.
--------------------------------------------------------------
💼 Real-world Example:
--------------------------------------------------------------
Imagine an expense approval workflow:
- Manager can approve expenses up to $1,000
- Director can approve up to $10,000
- CEO approves anything above that
Each approver either handles the request or forwards it up the chain.
--------------------------------------------------------------
❌ Without Chain of Responsibility:
--------------------------------------------------------------
We’d have a long if-else ladder like this:
if (amount <= 1000)
handleByManager();
else if (amount <= 10000)
handleByDirector();
else
handleByCEO();
Problems:
- Hard to extend (add new approver => modify old code)
- Violates Open/Closed Principle
- Not flexible or testable
- All logic tightly coupled
--------------------------------------------------------------
✅ With Chain of Responsibility:
--------------------------------------------------------------
Each approver is an independent handler.
You can easily add, remove, or reorder them without breaking code.
--------------------------------------------------------------
🧠 Use Cases:
--------------------------------------------------------------
- Approval systems (expense, leave, etc.)
- Logging frameworks (INFO → DEBUG → ERROR)
- Middleware request handling (e.g., HTTP filters)
- Access control and validation pipelines
--------------------------------------------------------------
🏗️ Structure:
--------------------------------------------------------------
Handler (Abstract class):
+ setNext(Handler)
+ handleRequest(request)
ConcreteHandler:
+ Handles the request if possible
+ Else passes it to the next handler
--------------------------------------------------------------
🧩 Example Implementation: Expense Approval System
--------------------------------------------------------------
*/
// -------------------- Abstract Handler ----------------------
class Approver {
protected:
shared_ptr<Approver> nextApprover;
public:
void setNext(shared_ptr<Approver> next) {
nextApprover = next;
}
virtual void approve(double amount) = 0;
virtual ~Approver() = default;
};
// -------------------- Concrete Handlers ---------------------
class Manager : public Approver {
public:
void approve(double amount) override {
if (amount <= 1000)
cout << "✅ Manager approved expense: $" << amount << endl;
else if (nextApprover)
nextApprover->approve(amount);
}
};
class Director : public Approver {
public:
void approve(double amount) override {
if (amount <= 10000)
cout << "✅ Director approved expense: $" << amount << endl;
else if (nextApprover)
nextApprover->approve(amount);
}
};
class CEO : public Approver {
public:
void approve(double amount) override {
cout << "✅ CEO approved expense: $" << amount << endl;
}
};
// -------------------- Client Code ----------------------------
int main() {
// Create the chain: Manager → Director → CEO
auto manager = make_shared<Manager>();
auto director = make_shared<Director>();
auto ceo = make_shared<CEO>();
manager->setNext(director);
director->setNext(ceo);
// Test requests of different amounts
double expenses[] = {500, 3000, 20000};
for (double amount : expenses) {
cout << "\nRequesting approval for $" << amount << endl;
manager->approve(amount);
}
return 0;
}
/*
--------------------------------------------------------------
🧾 Output:
--------------------------------------------------------------
Requesting approval for $500
✅ Manager approved expense: $500
Requesting approval for $3000
✅ Director approved expense: $3000
Requesting approval for $20000
✅ CEO approved expense: $20000
--------------------------------------------------------------
🚀 Benefits:
--------------------------------------------------------------
✅ Decouples sender and receiver
✅ Easy to extend new handlers
✅ Follows Open/Closed Principle
✅ Flexible and maintainable
--------------------------------------------------------------
⚠️ When NOT to Use:
--------------------------------------------------------------
- When the chain is too long (can reduce performance)
- When you always know exactly which handler to call
--------------------------------------------------------------
*/