Professional Documents
Culture Documents
Here are some of the most commonly used design patterns in OOP:
Creational Patterns:
Singleton Pattern: Ensures that a class has only one instance and provides a global point of
access to it.
Factory Method Pattern: Defines an interface for creating an object but allows subclasses to
alter the type of objects that will be created.
Abstract Factory Pattern: Provides an interface for creating families of related or dependent
objects without specifying their concrete classes.
Builder Pattern: Separates the construction of a complex object from its representation,
allowing the same construction process to create different representations.
Prototype Pattern: Creates new objects by copying an existing object, known as the
prototype.
Structural Patterns:
Adapter Pattern: Allows the interface of an existing class to be used as another interface.
Proxy Pattern: Provides a surrogate or placeholder for another object to control access to it.
Bridge Pattern: Separates an object’s abstraction from its implementation so that the two can
vary independently.
Behavioral Patterns:
Observer Pattern: Defines a one-to-many dependency between objects so that when one
object changes state, all its dependents are notified and updated automatically.
Strategy Pattern: Defines a family of algorithms, encapsulates each one, and makes them
interchangeable.
State Pattern: Allows an object to alter its behavior when its internal state changes.
Memento Pattern: Captures and externalizes an object's internal state so the object can be
restored to this state later.
Architectural Patterns:
Repository Pattern: Separates the logic that retrieves data from the underlying data store
from the rest of the application.
Design patterns are not mandatory in software development, but they are valuable tools for
improving code quality, reducing redundancy, and promoting good software design
principles. They offer proven, reusable solutions to common problems and can significantly
enhance the maintainability and extensibility of software systems.
Solid principles
The SOLID principles are a set of five design principles in object-oriented programming
(OOP) that aim to make software more maintainable, flexible, and understandable. These
principles were introduced by Robert C. Martin and represent a set of guidelines for writing
clean, maintainable, and scalable code. The acronym SOLID stands for the following
principles:
Software entities (such as classes, modules, and functions) should be open for extension but
closed for modification.
This principle encourages developers to design their software in a way that allows new
functionality to be added by creating new classes or components without altering existing,
stable code.
Liskov Substitution Principle (LSP):
Subtypes (derived or child classes) must be substitutable for their base types (parent or
superclasses) without affecting the correctness of the program.
In practical terms, this means that any derived class should be able to replace its base class
without causing unexpected or incorrect behavior.
Interface Segregation Principle (ISP):
Clients should not be forced to depend on interfaces they do not use. In other words, it's
better to have smaller, more specific interfaces rather than large, monolithic ones.
This principle encourages the creation of fine-grained interfaces tailored to the needs of the
client classes that implement them.
Dependency Inversion Principle (DIP):
High-level modules (such as abstractions and interfaces) should not depend on low-level
modules (concrete implementations). Both should depend on abstractions.
Abstractions (interfaces or abstract classes) should not depend on details; details should
depend on abstractions.
This principle promotes decoupling between high-level and low-level modules and
encourages the use of interfaces and dependency injection to make the system more flexible
and maintainable.
By adhering to these SOLID principles, software developers can create code that is more
modular, extensible, and easier to maintain. These principles are considered fundamental to
good object-oriented design and are widely used in software development to promote the
creation of robust and adaptable systems.
# Violation of SRP
class Employee:
def calculate_salary(self):
# Calculate the salary
pass
def save_to_database(self):
# Save employee data to the database
pass
# Adhering to SRP
class Employee:
def calculate_salary(self):
# Calculate the salary
pass
class EmployeeDatabase:
def save_to_database(self, employee):
# Save employee data to the database
pass
# Violation of OCP
class Circle:
def draw(self):
# Draw a circle
class Square:
def draw(self):
# Draw a square
class Circle(Shape):
def draw(self):
# Draw a circle
class Square(Shape):
def draw(self):
# Draw a square
# Violation of LSP
class Bird:
def fly(self):
pass
class Ostrich(Bird):
def fly(self):
# Ostriches can't fly, so this is incorrect
# Adhering to LSP
class Bird:
def move(self):
pass
class Sparrow(Bird):
def move(self):
# Sparrows can fly
class Ostrich(Bird):
def move(self):
# Ostriches can't fly, so they run
# Violation of ISP
class Worker:
def work(self):
pass
def eat(self):
pass
# Adhering to ISP
class Workable:
def work(self):
pass
class Eatable:
def eat(self):
pass
# Violation of DIP
class LightBulb:
def turn_on(self):
pass
class Switch:
def __init__(self, bulb):
self.bulb = bulb
def operate(self):
if self.bulb.is_on():
self.bulb.turn_off()
else:
self.bulb.turn_on()
# Adhering to DIP
class Switchable:
def turn_on(self):
pass
def turn_off(self):
pass
class LightBulb(Switchable):
def is_on(self):
pass
class Switch:
def __init__(self, device):
self.device = device
def operate(self):
if self.device.is_on():
self.device.turn_off()
else:
self.device.turn_on()
Creational patterns
Singleton Pattern:
Example in Python:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
Defines an interface for creating objects but lets subclasses decide which class to
instantiate.
Example in Python:
from abc import ABC, abstractmethod
class Creator(ABC):
@abstractmethod
def factory_method(self):
pass
class ConcreteCreatorA(Creator):
def factory_method(self):
return ConcreteProductA()
class ConcreteCreatorB(Creator):
def factory_method(self):
return ConcreteProductB()
Provides an interface for creating families of related or dependent objects without specifying
their concrete classes.
Example in Python:
class AbstractFactory(ABC):
@abstractmethod
def create_product_a(self):
pass
@abstractmethod
def create_product_b(self):
pass
class ConcreteFactory1(AbstractFactory):
def create_product_a(self):
return ProductA1()
def create_product_b(self):
return ProductB1()
Builder Pattern:
Example in Python:
class Director:
def __init__(self, builder):
self.builder = builder
def construct(self):
self.builder.build_part_a()
self.builder.build_part_b()
class Builder:
def build_part_a(self):
pass
def build_part_b(self):
pass
Prototype Pattern:
Example in Python:
import copy
class Prototype:
def clone(self):
return copy.copy(self)
Structural Patterns:
Adapter Pattern:
Example in Python:
class Target:
def request(self):
pass
class Adaptee:
def specific_request(self):
pass
class Adapter(Target):
def __init__(self, adaptee):
self.adaptee = adaptee
def request(self):
self.adaptee.specific_request()
Decorator Pattern:
Example in Python:
class Component:
def operation(self):
pass
class ConcreteComponent(Component):
def operation(self):
pass
class Decorator(Component):
def __init__(self, component):
self._component = component
def operation(self):
self._component.operation()
Composite Pattern:
Example in Python:
class Component:
def operation(self):
pass
class Leaf(Component):
def operation(self):
pass
class Composite(Component):
def operation(self):
for component in self._children:
component.operation()
Proxy Pattern:
Example in Python:
class Subject:
def request(self):
pass
class RealSubject(Subject):
def request(self):
pass
class Proxy(Subject):
def __init__(self, real_subject):
self._real_subject = real_subject
def request(self):
self._real_subject.request()
Bridge Pattern:
Example in Python:
class Abstraction:
def __init__(self, implementation):
self._implementation = implementation
def operation(self):
self._implementation.operation_implementation()
class Implementor:
def operation_implementation(self):
pass
class ConcreteImplementorA(Implementor):
def operation_implementation(self):
pass