Behavioral design patterns are concerned with how objects interact and communicate with each other. These patterns help manage complex communication and control flows in a software system. By separating responsibilities and promoting loose coupling, behavioral patterns make systems easier to understand, extend, and maintain.
In this guide, we will explore key behavioral design patterns with examples in Python. These include:
This pattern allows a request to pass through a chain of handlers. Each handler decides either to process the request or pass it along the chain.
class Handler:
def __init__(self, successor=None):
self.successor = successor
def handle(self, request):
handled = self._handle(request)
if not handled and self.successor:
self.successor.handle(request)
def _handle(self, request):
raise NotImplementedError
class ConcreteHandler1(Handler):
def _handle(self, request):
if 0 < request <= 10:
print(f"Handler1 handled request: {request}")
return True
return False
class ConcreteHandler2(Handler):
def _handle(self, request):
if 10 < request <= 20:
print(f"Handler2 handled request: {request}")
return True
return False
handler_chain = ConcreteHandler1(ConcreteHandler2())
handler_chain.handle(5)
handler_chain.handle(15)
The Command pattern turns a request into an object containing all the information needed to perform an action.
class Light:
def on(self):
print("Light is ON")
def off(self):
print("Light is OFF")
class Command:
def execute(self):
pass
class LightOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.on()
class LightOffCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.off()
class RemoteControl:
def submit(self, command):
command.execute()
light = Light()
on = LightOnCommand(light)
off = LightOffCommand(light)
remote = RemoteControl()
remote.submit(on)
remote.submit(off)
The Interpreter pattern provides a way to evaluate language grammar or expressions. It defines a representation for grammar and interprets it accordingly.
class Expression:
def interpret(self, context):
pass
class Number(Expression):
def __init__(self, value):
self.value = value
def interpret(self, context):
return self.value
class Add(Expression):
def __init__(self, left, right):
self.left = left
self.right = right
def interpret(self, context):
return self.left.interpret(context) + self.right.interpret(context)
expr = Add(Number(10), Number(20))
print(expr.interpret({}))
The Iterator pattern provides a way to access elements of a collection sequentially without exposing its underlying representation.
class CountDown:
def __init__(self, start):
self.start = start
def __iter__(self):
self.n = self.start
return self
def __next__(self):
if self.n <= 0:
raise StopIteration
result = self.n
self.n -= 1
return result
for i in CountDown(5):
print(i)
The Mediator pattern defines an object that coordinates interaction between objects, reducing their direct dependencies.
class ChatMediator:
def __init__(self):
self.users = []
def register(self, user):
self.users.append(user)
def send(self, msg, sender):
for user in self.users:
if user != sender:
user.receive(msg)
class User:
def __init__(self, name, mediator):
self.name = name
self.mediator = mediator
self.mediator.register(self)
def send(self, msg):
print(f"{self.name} sends: {msg}")
self.mediator.send(msg, self)
def receive(self, msg):
print(f"{self.name} receives: {msg}")
mediator = ChatMediator()
alice = User("Alice", mediator)
bob = User("Bob", mediator)
alice.send("Hello Bob!")
bob.send("Hi Alice!")
The Memento pattern captures and restores an object's internal state without violating encapsulation.
class Memento:
def __init__(self, state):
self._state = state
def get_state(self):
return self._state
class Originator:
def __init__(self):
self._state = ""
def set_state(self, state):
self._state = state
def save(self):
return Memento(self._state)
def restore(self, memento):
self._state = memento.get_state()
originator = Originator()
originator.set_state("State1")
memento = originator.save()
originator.set_state("State2")
print("Current:", originator._state)
originator.restore(memento)
print("Restored:", originator._state)
The Observer pattern defines a one-to-many dependency so when one object changes state, all its dependents are notified.
class Subject:
def __init__(self):
self._observers = []
def register(self, observer):
self._observers.append(observer)
def notify(self, data):
for obs in self._observers:
obs.update(data)
class Observer:
def update(self, data):
print(f"Received: {data}")
subject = Subject()
obs1 = Observer()
obs2 = Observer()
subject.register(obs1)
subject.register(obs2)
subject.notify("Event occurred")
The State pattern allows an object to alter its behavior when its internal state changes. The object appears to change its class.
class State:
def handle(self):
pass
class StateA(State):
def handle(self):
print("Handling in State A")
class StateB(State):
def handle(self):
print("Handling in State B")
class Context:
def __init__(self):
self.state = StateA()
def set_state(self, state):
self.state = state
def request(self):
self.state.handle()
ctx = Context()
ctx.request()
ctx.set_state(StateB())
ctx.request()
The Strategy pattern defines a family of algorithms and lets the algorithm vary independently from clients that use it.
class Strategy:
def do_operation(self, a, b):
pass
class AddStrategy(Strategy):
def do_operation(self, a, b):
return a + b
class SubtractStrategy(Strategy):
def do_operation(self, a, b):
return a - b
class Context:
def __init__(self, strategy):
self.strategy = strategy
def execute(self, a, b):
return self.strategy.do_operation(a, b)
context = Context(AddStrategy())
print(context.execute(10, 5))
context = Context(SubtractStrategy())
print(context.execute(10, 5))
The Template Method pattern defines the skeleton of an algorithm and allows subclasses to redefine specific steps.
class Game:
def play(self):
self.start()
self.playing()
self.end()
def start(self):
pass
def playing(self):
pass
def end(self):
pass
class Cricket(Game):
def start(self):
print("Cricket Game Started")
def playing(self):
print("Cricket Game Playing")
def end(self):
print("Cricket Game Ended")
game = Cricket()
game.play()
The Visitor pattern lets you define new operations on object structures without changing the classes.
class Element:
def accept(self, visitor):
visitor.visit(self)
class ConcreteElementA(Element):
def operation(self):
return "Element A"
class ConcreteElementB(Element):
def operation(self):
return "Element B"
class Visitor:
def visit(self, element):
print(f"Visited {element.operation()}")
elementA = ConcreteElementA()
elementB = ConcreteElementB()
visitor = Visitor()
elementA.accept(visitor)
elementB.accept(visitor)
Behavioral design patterns are crucial for managing interactions between objects and controlling the flow of a program. They help in structuring communication in a decoupled, flexible, and scalable manner. Python's dynamic nature and support for first-class functions make implementing these patterns more natural compared to statically typed languages.
This document introduced and explained the key behavioral design patterns, including real-world analogies and clear code implementations. Mastering these patterns empowers developers to build maintainable and robust software systems.
Python is commonly used for developing websites and software, task automation, data analysis, and data visualisation. Since it's relatively easy to learn, Python has been adopted by many non-programmers, such as accountants and scientists, for a variety of everyday tasks, like organising finances.
Learning Curve: Python is generally considered easier to learn for beginners due to its simplicity, while Java is more complex but provides a deeper understanding of how programming works.
The point is that Java is more complicated to learn than Python. It doesn't matter the order. You will have to do some things in Java that you don't in Python. The general programming skills you learn from using either language will transfer to another.
Read on for tips on how to maximize your learning. In general, it takes around two to six months to learn the fundamentals of Python. But you can learn enough to write your first short program in a matter of minutes. Developing mastery of Python's vast array of libraries can take months or years.
6 Top Tips for Learning Python
The following is a step-by-step guide for beginners interested in learning Python using Windows.
Best YouTube Channels to Learn Python
Write your first Python programStart by writing a simple Python program, such as a classic "Hello, World!" script. This process will help you understand the syntax and structure of Python code.
The average salary for Python Developer is βΉ5,55,000 per year in the India. The average additional cash compensation for a Python Developer is within a range from βΉ3,000 - βΉ1,20,000.
Copyrights © 2024 letsupdateskills All rights reserved