Skip to content

Commit 4dda689

Browse files
committed
added chain of responsibility pattern
1 parent cd42eea commit 4dda689

File tree

5 files changed

+141
-0
lines changed

5 files changed

+141
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ Common GOF Patterns implemented in Python
99
* [Prototype](prototype)
1010
* Behavioural
1111
* [Command](command)
12+
* [Chain of Responsibiltiy](chain_of_responsibility)

chain_of_responsibility/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Chain of Responsibility Design Pattern
2+
3+
Chain of responsibility pattern is a behavioral pattern used to achieve loose coupling
4+
in software design.
5+
Example, a request from a client is passed to a chain of objects to process them.
6+
The objects in the chain will decide themselves how the request is handled and/or
7+
passed to the next processor in the chain.
8+
9+
![Chain of Responsibility UML Diagram in the context of an ATM](atm.png)
10+
11+
```bash
12+
$ python atm.py
13+
Enter amount to withdrawal
14+
130
15+
Dispensing 2 £50 note
16+
Dispensing 1 £20 note
17+
Dispensing 1 £10 note
18+
```

chain_of_responsibility/atm.png

22.2 KB
Loading

chain_of_responsibility/atm.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""Chain of Responsibility Pattern
2+
Chain of responsibility pattern is a behavioral pattern used to achieve loose coupling
3+
in software design.
4+
Example, a request from a client is passed to a chain of objects to process them.
5+
The objects in the chain will decide themselves how the request is handled and/or
6+
passed to the next processor in the chain.
7+
"""
8+
9+
from abc import ABCMeta, abstractstaticmethod
10+
11+
12+
class IDispenseChain(metaclass=ABCMeta):
13+
14+
@abstractstaticmethod
15+
def set_next_chain(next_chain):
16+
"""Set the next processor in the chain"""
17+
18+
@abstractstaticmethod
19+
def dispense(currency):
20+
"""Dispense the amount"""
21+
22+
23+
class Dispenser50(IDispenseChain):
24+
25+
def __init__(self):
26+
self.chain = None
27+
28+
def set_next_chain(self, next_chain):
29+
self.chain = next_chain
30+
31+
def dispense(self, amount):
32+
if amount >= 50:
33+
num = amount // 50
34+
remainder = amount % 50
35+
print(f"Dispensing {num} £50 note")
36+
if remainder != 0:
37+
self.chain.dispense(remainder)
38+
else:
39+
self.chain.dispense(amount)
40+
41+
42+
class Dispenser20(IDispenseChain):
43+
44+
def __init__(self):
45+
self.chain = None
46+
47+
def set_next_chain(self, next_chain):
48+
self.chain = next_chain
49+
50+
def dispense(self, amount):
51+
if amount >= 20:
52+
num = amount // 20
53+
remainder = amount % 20
54+
print(f"Dispensing {num} £20 note")
55+
if remainder != 0:
56+
self.chain.dispense(remainder)
57+
else:
58+
self.chain.dispense(amount)
59+
60+
61+
class Dispenser10(IDispenseChain):
62+
63+
def __init__(self):
64+
self.chain = None
65+
66+
def set_next_chain(self, next_chain):
67+
self.chain = next_chain
68+
69+
def dispense(self, amount):
70+
if amount >= 10:
71+
num = amount // 10
72+
remainder = amount % 10
73+
print(f"Dispensing {num} £10 note")
74+
if remainder != 0:
75+
self.chain.dispense(remainder)
76+
else:
77+
self.chain.dispense(amount)
78+
79+
80+
class ATMDispenserChain:
81+
82+
def __init__(self):
83+
# initialize the chain
84+
85+
self.chain1 = Dispenser50()
86+
self.chain2 = Dispenser20()
87+
self.chain3 = Dispenser10()
88+
89+
# set the chain of responsibility
90+
self.chain1.set_next_chain(self.chain2)
91+
self.chain2.set_next_chain(self.chain3)
92+
93+
94+
if __name__ == "__main__":
95+
96+
ATM = ATMDispenserChain()
97+
98+
print("Enter amount to withdrawal")
99+
AMOUNT = int(input())
100+
if AMOUNT % 10 != 0:
101+
print("Amount should be in multiple of 10s.")
102+
# process the request
103+
ATM.chain1.dispense(AMOUNT)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
digraph "classes_atm" {
2+
charset="utf-8"
3+
rankdir=BT
4+
5+
"Dispenser50" [label="{Dispenser50|chain : NoneType\l|dispense()\lset_next_chain()\l}", shape="record"];
6+
"Dispenser10" [label="{Dispenser10|chain : NoneType\l|dispense()\lset_next_chain()\l}", shape="record"];
7+
"Dispenser20" [label="{Dispenser20|chain : NoneType\l|dispense()\lset_next_chain()\l}", shape="record"];
8+
"IDispenseChain" [label="{IDispenseChain|\l|dispense()\lset_next_chain()\l}", shape="record"];
9+
10+
"ATMDispenserChain" [label="{ATMDispenserChain|chain1\lchain2\lchain3\l|}", shape="record"];
11+
12+
{ "Dispenser10" "Dispenser20" "Dispenser50" } -> "IDispenseChain" [arrowhead="empty", arrowtail="none"];
13+
14+
"Dispenser10" -> "ATMDispenserChain" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="chain3", style="solid"];
15+
"Dispenser20" -> "ATMDispenserChain" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="chain2", style="solid"];
16+
"Dispenser50" -> "ATMDispenserChain" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="chain1", style="solid"];
17+
18+
19+
}

0 commit comments

Comments
 (0)