A Catalog For Design Patterns in Python

      No Comments on A Catalog For Design Patterns in Python

Exploring Design Patterns: Concepts, Analogies, Advantages, Disadvantages, and Real-Life Use Cases.



In software engineering, design patterns are reusable solutions to commonly occurring problems in software design. There are various types of design patterns, each addressing different aspects of software development.

I have more detailed articles about common design patterns. In this blog post, I will explore each of these design patterns categorically, including their definitions, analogies from real life, advantages, disadvantages, and use cases in real-world software engineering.

My goal here is to bring these patterns together as if they were in a catalog.

  • Creational Design Patterns
  • Structural Design Patterns
  • Behavioral Design Patterns
  • Others

Creational Design Patterns

Creational design patterns are responsible for providing a structured approach to object creation.

  • Singleton
  • Factory
  • Abstract Factory
  • Prototype
  • Builder

Singleton

Design Patterns in Python: Singleton Pattern

Implementation of Singleton Design Pattern in Python

levelup.gitconnected.com

  • Characteristic: It ensures only one instance of a class is created and provides a global point of access to that instance.
  • Analogy: President of a country. No matter where you go in the country, the president is the same person, and everyone refers to him or her as the president.
  • Biggest Advantage: There is only one instance of a class throughout the entire application.
  • Headache: Potential issues related to thread safety.
  • Use Case: All parts of the application are working with the same shared resource. For example;

Database connection: only one connection is created and shared throughout the application.

Configuration settings: settings like server addresses, API keys, or other information that needs to be shared throughout the application.

Logging: all logging messages are sent to a single instance.

Caching: all data is stored in a single instance.

State management: manage the state of the application in a single center.

Singleton. Source

Factory

Design Patterns in Python: Factory & Abstract Factory Patterns

Implementation of Factory and Abstract Factory Patterns in Python

levelup.gitconnected.com

  • Characteristic: It provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.
  • Analogy: A pizza restaurant. The restaurant provides an interface for creating pizzas. The customer doesn’t need to know how the pizza is made or what specific ingredients are used, they simply need to order the pizza they want from the menu.
  • Biggest Advantage: A modular and scalable way to create objects.
  • Headache: Be careful about the subclass explosion.
  • Use Cases: To create complex objects without exposing the instantiation logic. For example;

Complex and variety of objects: A software application that needs to generate reports from multiple data sources, with different data formatting and layout requirements.

GUI widgets: We can create different types of GUI widgets based on user input, without calling code and needing to know the specific implementation of each widget.

Web service clients: We can interact with multiple web services based on the desired protocol and endpoint.

Factory. Source

Abstract Factory

Design Patterns in Python: Factory & Abstract Factory Patterns

Implementation of Factory and Abstract Factory Patterns in Python

levelup.gitconnected.com

  • Characteristic: The factory pattern creates individual objects, while the Abstract Factory pattern creates families of related objects.
  • Analogy: A Dinner Party. You need to choose a set of dishes, glasses, and silverware that complement each other and create a unified aesthetic. A separate factory object will be responsible for creating a specific type of object. For example, the DishFactory would create plates, bowls, and serving dishes with a matching design and color scheme, while the GlassFactory would create glasses and stemware that also match the overall aesthetic.
  • Biggest Advantage: a way to create families of related objects that are designed to work together.
  • Headache: Complexity, particularly if many related object families need to be created and managed.
  • Use Cases: To create a set of related objects that work together. For example;

Creating families of related GUI elements, such as windows, buttons, and text fields, that work together and have a consistent look and feel.

Abstract Factory. Source

Prototype

Design Patterns in Python: Prototype Pattern

Implementation of Prototype Pattern in Python

python.plainenglish.io

  • Characteristic: focuses on creating new objects by cloning existing ones, rather than creating them from scratch or managing a single instance.
  • Analogy: Locksmith. A locksmith uses a key duplicating machine, which creates a copy of the original key by tracing its shape and cutting a new key to the same size and shape. This is much faster and more efficient than creating a new key from scratch.
  • Biggest Advantage: It allows for the efficient creation of new objects by cloning existing ones, without the need to go through the costly and complex creation process each time.
  • Headache: If the object is complex enough, then probably you will end up getting circular reference problems.
  • Use Cases: To create new objects by cloning existing ones quickly, and customize them as needed.

Graphic design software: Graphic design software use Prototype design pattern to create and manage graphical objects, such as shapes and icons.

Video game development: Video game development engines use Prototype design pattern to create and manage game objects, such as characters and weapons.

Prototype. Source

Builder

Design Patterns in Python: Builder Pattern

Implementation of the Builder Pattern in Python Language

python.plainenglish.io

  • Characteristic: separates the construction of a complex object from its representation.
  • Analogy: A car manufacturing process. The process of manufacturing a car involves multiple steps, such as selecting the engine, choosing the exterior color, adding features like a sunroof or leather seats, and so on. For example, there might be an EngineBuilder class that defines the process for selecting and installing the car’s engine, a ColorBuilder class that defines the process for choosing the exterior color, and so on. Each builder class can have its own methods and properties for configuring the specific aspect of the car that it represents.
  • Biggest Advantage: Separation of concerns. It allows for the creation of complex objects step by step with many configuration options, without requiring the client code to be aware of the details of the construction process.
  • Headache: A complex way of creating for simpler objects. Don’t do overengineering.
  • Use Cases: To create complex objects with many configuration options or variations.

Document generators: Document generation software, such as PDF or HTML generators, can use the Builder pattern to create complex documents with many components such as headers, footers, tables, images, and text blocks.

Composite objects: In some cases, objects may contain other objects, such as a menu item that contains multiple sub-items.

Builder. Source

Structural Design Patterns

Structural design patterns focus on how objects and classes are composed to form larger structures, such as relationships between objects, interfaces between systems, and object hierarchies. These patterns help to identify common relationships and provide standardized solutions that can be used to build and maintain software systems.

  • Flyweight
  • Adapter
  • Composite
  • Facade
  • Proxy
  • Decorator
  • Bridge

Flyweight

Design Patterns in Python: Flyweight Pattern

Implementation of Flyweight Design Pattern in Python

towardsdev.com

  • Characteristic: It minimizes memory usage and improves performance by sharing as much data as possible with similar objects. (Prototype design pattern sounds similar, but it was about the initial creation of any objects. The purpose is different. The Flyweight pattern is used to reduce memory usage by sharing common data among similar objects, while the Prototype pattern is used to create new objects by copying existing ones.)
  • Analogy: Summaries of books in a library. Instead of creating a new summary for each book request, you could use the Flyweight design pattern to create a separate Flyweight object that contains commonly used data, such as the book title, author, and publisher.
  • Biggest Advantage: Sharing common data among similar objects.
  • Headache: It is harder to maintain because we split the objects into intrinsic and extrinsic states.
  • Use Cases: Those objects that have shared characteristics that can be separated into intrinsic and extrinsic states.

Computer games, where a large number of similar objects, such as enemy sprites or terrain tiles, need to be created and managed efficiently.

Flyweight. Source

Adapter

Design Patterns in Python: Adapter Pattern

Implementation of Adapter Design Pattern in Python

levelup.gitconnected.com

  • Characteristic: It allows incompatible interfaces to work together by creating an intermediate object that translates between the two interfaces.
  • Analogy: Chargers. You might use an adapter that can connect your charger to a foreign outlet.
  • Biggest Advantage: It is easier to integrate different components or modules in a software system without having to change their source code.
  • Headache: An extra layer of abstraction.
  • Use Cases: To solve compatibility issues between different interfaces, classes, or systems.

Legacy system integration: When a legacy system needs to be integrated with a new system, the adapter pattern can be used to bridge the gap between the old and new systems.

Library compatibility: When two libraries have different interfaces but need to be used together, an adapter can be used to make them compatible with each other.

Third-party API integration: When working with third-party APIs, an adapter can be used to convert the API’s interface to the interface that the software system requires.

Adapter. Source

Composite

Design Patterns in Python: Composite Pattern

Implementation of Composite Design Pattern in Python Language

python.plainenglish.io

  • Characteristic: It allows us to treat a group of objects the same way as a single instance of an object.
  • Analogy: A company (any hierarchical organization). The company represents the composite object, which can contain multiple departments (leaf objects) that can contain multiple employees (leaf objects). The department and employee objects can have different properties and methods, but they all share a common interface (e.g., they all have a name and can perform work).
  • Biggest Advantage: A client can interact with individual objects in the same way.
  • Headache: Providing a common interface for classes with vastly different functionalities can be challenging, and overgeneralizing the component interface to accommodate such scenarios can make it difficult to understand.
  • Use Cases: A tree-like hierarchical structure, i.e. file systems, GUIs…
Composite. Source

Facade

Design Patterns in Python: Facade Pattern

Implementation of Facade Design Pattern in Python

faun.pub

  • Characteristic: a simplified interface to a complex system of classes.
  • Analogy: Waiter. In a restaurant, there are many different departments, such as the kitchen, the wait staff, and the bar. Each department has its own specific tasks and responsibilities. However, from the customer’s perspective, they only need to interact with the waiter or the menu to get what they want.
  • Biggest Advantage: A simplified interface for the clients.
  • Headache: Too much coupling.
  • Use Cases: Client-oriented complex systems.

A facade object can be defined to simplify the usage of complex libraries or frameworks.

A simplified, user-friendly interface, or facade, can be provided to users to interact with the operating system, hiding the complexity of the underlying system.

E-commerce websites often involve complex workflows that require interaction with various services such as payment gateways, shipping providers, and inventory management systems. A facade can be used to provide a simplified interface to these services, allowing the e-commerce website to focus on its core functionality.

Media players have a lot of functionality such as play, pause, stop, rewind, fast-forward, etc. A facade can be used to provide a simple interface for the user to control the media player.

Facade. Source

Proxy

Design Patterns in Python: Proxy Pattern

Implementation of Proxy Design Pattern in Python

python.plainenglish.io

  • Characteristic: A placeholder object to control access to another object. The facade pattern sounds similar. However, the facade provides a simplified interface to a subsystem of interfaces, whereas the proxy provides an interface to access an object (has the same interface), controls access to it, and provides additional functionality.
  • Analogy: An online ticket agency. A ticketing agency acts as a proxy between the visitors and the museum, handling ticket purchases, managing queues, and providing necessary information to visitors, such as park timings, exhibitions, etc.
  • Biggest Advantage: Controlling access to an object.
  • Headache: It will impact performance when the proxy performs additional tasks before passing requests to the real object.
  • Use Cases: remote proxies for managing objects in a different address space, virtual proxies for expensive resources, protection proxies for access control, cache proxies for improving performance, and logging proxies for debugging and tracing…
Proxy. Source

Decorator

Design Patterns in Python: Decorator Pattern

Implementation of Decorator Design Pattern in Python

faun.pub

  • Characteristic: It attaches additional responsibilities to an object.
  • Analogy: A birthday cake. You bought a cake from the bakery and put some candles on it.
  • Biggest Advantage: Without creating a new subclass, it’s possible to enhance the functionality of an object by extending its behavior.
  • Headache: Code can be pretty ugly.
  • Use Cases: To add filters to images or videos, add additional functionality to text editors or word processors, and customize the behavior of user interfaces by adding or removing components dynamically.
Decorator. Source

Bridge

Design Patterns in Python: Bridge Pattern

Implementation of Bridge Design Pattern in Python

python.plainenglish.io

  • Characteristic: Decoupling an abstraction from its implementation.
  • Analogy: Remote controller. Let’s say you have a remote control that can operate different devices such as a TV, a DVD player, and a sound system. The remote control itself is the abstraction, and each of the devices it can operate is the implementation. The bridge pattern allows you to change the remote control’s behavior independently of the device it operates by separating the abstraction and implementation into two different hierarchies, allowing for more flexibility and extensibility in the design.
  • Biggest Advantage: It separates an abstraction from its implementation so that both can be modified independently, making the system more flexible and adaptable to changes.
  • Headache: Too much abstraction is hard to swallow sometimes.
  • Use Cases: In cases where there are multiple implementations of a given abstraction. One common use case is in GUI frameworks where a GUI component (abstraction) needs to be rendered differently on different platforms (implementations). Another use case is in database drivers, where a database driver (abstraction) needs to work with different database management systems (implementations).
Bridge. Source

Behavioral Design Patterns

These patterns handle communication, interaction, and responsibilities between objects in a system.

  • Strategy
  • Command
  • Iterator
  • Template Method
  • Observer
  • Memento
  • Mediator
  • Chain of Responsibility
  • Visitor
  • State

Strategy

Design Patterns in Python: Strategy Pattern

Implementation of Strategy Pattern in Python

levelup.gitconnected.com

  • Characteristic: Use interchangeably a family of objects.
  • Analogy: Preparing a meal. For example, when making a salad, you’ll use a knife to chop the vegetables, but when making a soup, you’ll use a blender to puree the ingredients. In this case, the tools and ingredients are the “strategies” that you can use to prepare the meal, and the type of dish you’re making is the “context” that determines which strategies are needed.
  • Biggest Advantage: It allows for easy swapping of algorithms or behaviors at runtime without changing the context class.
  • Headache: It is overengineering to use it in situations that do not vary widely.
  • Use Cases: We can use it in scenarios where different algorithms can be applied to solve a problem, and the choice of algorithm can vary based on runtime conditions or requirements.

Payment processing: A payment processing system may use the strategy pattern to encapsulate different payment methods such as credit cards, PayPal, or bank transfers. This allows the system to use different payment methods based on the user’s preference or availability.

Strategy. Source

Command

Design Patterns in Python: Command Pattern

Implementation of Command Design Pattern in Python

levelup.gitconnected.com

  • Characteristic: It allows for the parameterization of clients with different requests, queue or log requests, and support for undoable operations.

The strategy pattern sounds similar. However, the intent is different. The strategy pattern focuses on providing alternative algorithms or strategies for a particular task, while the command pattern focuses on encapsulating a request as an object to enable undo/redo operations or to implement logging and transactional systems.

The Command design pattern enables you to convert any operation into an object, where the parameters of the operation become fields of that object. This conversion allows you to defer the execution of the operation, store the history of commands, send commands to remote services, etc. In contrast, the Strategy design pattern describes different ways of achieving the same objective, allowing you to swap these algorithms within a single context class.

  • Analogy: A chef.

The Command design pattern would allow us to create commands that represent specific actions, such as cutting vegetables or adding seasoning to a dish. We can then create an order of commands that the Chef will execute to cook the dish. For example, we can have a CutVegetablesCommand and an AddSeasoningCommand, which can be added to a list of commands that the Chef will execute in the order they were added.

The Strategy design pattern would allow us to define different cooking strategies, such as boiling, frying, and baking, each represented by a separate class that implements a common interface. The Chef class can then choose which strategy to use at runtime by setting an instance of one of the strategy classes. For example, the Chef can cook pasta by boiling it or frying it, depending on the customer’s preference.

  • Biggest Advantage: It is easier to add new commands, queue or log commands for later execution, or undo/redo commands as needed.
  • Headache: An additional layer of abstraction can make things more complicated.
  • Use Cases: Undo/redo functionality, queuing requests, transaction management…
Command. Source

Iterator

Design Patterns in Python: Iterator Pattern

Implementation of Iterator Design Pattern in Python Language

towardsdev.com

  • Characteristic: Navigate over a sequence without exposing its underlying implementation.
  • Analogy: Any iteration over a sequence. To calculate the average grade of the class, you need to go through each student’s grade and add them up. You can use an iterator to iterate over each student’s grade and calculate the average more efficiently.
  • Biggest Advantage: a standard interface for traversing a collection of objects.
  • Headache: Can be less efficient.
  • Use Cases: Any sequence that needs to be traversed.
Iterator. Source

Template Method

Design Patterns in Python: Template Method Pattern

Implementation of Template Method Design Pattern in Python

awstip.com

  • Characteristic: It defines the skeleton of an algorithm in a superclass but lets subclasses override specific steps of the algorithm without changing its structure.
  • Analogy: Food Recipe. You have a recipe that outlines the steps to follow to bake a cake. The recipe is an example of a template method. The recipe gives you a structure to follow, such as the ingredients to use, the order in which to mix them, and how long to bake the cake. However, there are some steps where you have some flexibility, such as the type of flavoring you want to use, or the design of the frosting.
  • Biggest Advantage: It is possible to make parts of a complex algorithm that can be changed by the clients while other parts remain unaffected, thus minimizing the impact of changes to the overall algorithm.
  • Headache: It can lead to a rigid design, where it may be difficult to add new steps to the algorithm without making significant changes to the existing code.
  • Use Cases: A common structure for algorithms that need to be customized in different ways. It can be used for creating workflows for complex processes, implementing algorithms in scientific or financial applications, and defining the structure of user interfaces in graphical applications. It can also be used to create reusable code that can be shared across multiple projects or applications.
Template Method. Source

Observer

Design Patterns in Python: Observer Pattern

Implementation of the Observer Design Pattern in Python

python.plainenglish.io

  • Characteristic: Multiple objects are notified and updated automatically when a single object changes its state.
  • Analogy: Subscription. When you subscribe to a newspaper, you become an observer or subscriber to that newspaper. The newspaper is the subject, and the subscribers are the observers. Whenever the newspaper publishes a new edition, it notifies all its subscribers about the new release, and each subscriber receives a copy of the newspaper.
  • Biggest Advantage: Loose coupling.
  • Headache: This could be a performance issue if there are many subscribers.
  • Use Cases: An object needs to notify other objects (observers) about its state changes.

Event-driven systems: In GUI frameworks, user interfaces generate events that are captured and processed by observers, which in turn update the display or execute other actions.

Message brokers: A message broker can use the observer pattern to notify subscribers about incoming messages.

Observer. Source

Memento

Design Patterns in Python: Memento Pattern

Implementation of the Memento Design Pattern in Python

blog.devgenius.io

  • Characteristic: It allows you to save and restore the state of an object without exposing the details of its implementation.
  • Analogy: Saving a game. A game can use a memento design pattern to save the current state of the player’s progress in a “save file”.
  • Biggest Advantage: Saving the state without violating encapsulation.
  • Headache: Can consume too much memory.
  • Use Cases: Games, database systems, transaction management.
Memento. Source

Mediator

Design Patterns in Python: Mediator Pattern

Mediator Design Pattern Explained.

faun.pub

  • Characteristic: It enables objects to communicate with each other through a mediator object
  • Analogy: A team leader. Instead of team members communicating directly with each other, they communicate with the team leader, who then relays the information to the appropriate team members. This reduces the coupling between team members and allows them to focus on their specific tasks without being bogged down by communication with other team members.
  • Biggest Advantage: Loose coupling between objects by centralizing their communication through a mediator object.
  • Headache: A Mediator either dies a hero or lives long enough to see itself become the villain. Get fats over time.
  • Use Cases: When communication is important. For example, in a distributed system, a mediator can be used to coordinate the communication between different nodes or services. Other potential use cases for the mediator pattern include chat applications, event-driven systems, and workflow management systems.
Mediator. Source

Chain of Responsibility

Design Patterns in Python: Chain of Responsibility

Explanation and Implementation of Chain of Responsibility Design Pattern in Python

towardsdev.com

  • Characteristic: A chain of objects, each of which can handle the request or pass it on to the next object in the chain.
  • Analogy: A production line. Each worker is responsible for a specific task in the production process, such as painting, welding, or packaging. If a worker encounters a problem or a defect in their task, they can pass the product to the next worker in the line who is responsible for fixing the issue. If that worker cannot fix the issue, they can pass the product to the next worker in the line, and so on, until the problem is resolved or the product is discarded.
  • Biggest Advantage: It is possible to manage the sequence of how requests are processed.
  • Headache: Chain design is important. Hard to maintain.
  • Use Cases: In situations where a request needs to be handled by multiple objects in a particular order. Input validation, logging, exception handling.
Chain of responsibility. Source

Visitor

Design Patterns in Python: Visitor Pattern

The Visitor Design Pattern Explained and Implemented

python.plainenglish.io

  • Characteristic: It separates the algorithm from the object structure by allowing an external object (the visitor) to visit and operate on the elements of that structure.
  • Analogy: Inspection. You go to the production line and visit each workstation, examining the products and marking them as pass or fail based on specific criteria. In this scenario, you are the visitor and the workstations are the elements being visited.
  • Biggest Advantage: It allows the addition of new operations to an object structure without modifying the objects themselves.
  • Headache: It can become cumbersome to update the visitor interface and all of its implementations when there are updates.
  • Use Cases: Visitor design pattern is often used in compilers, interpreters, or other tools that work with complex abstract syntax trees (ASTs).
Visitor. Source

State

Design Patterns in Python: State Pattern

The State Design Pattern Explained and Implemented in Python

medium.com

  • Characteristic: It allows an object to change its behavior based on its internal state.
  • Analogy: Traffic lights. Each state of the traffic light controls the behavior of the drivers, who must follow the rules and regulations associated with each state.
  • Biggest Advantage: It allows an object to alter its behavior when its internal state changes, without changing its class.
  • Headache: States and state transitions must be clear.
  • Use Cases: It can be used in various situations where an object’s behavior changes based on its internal state, such as in video games where characters may have different behaviors based on their health status.
State. Source

Others

  • Null Object
  • Repository
  • Unit of Work

Null Object

Design Patterns in Python: Null Object Pattern

Null Object Design Pattern Explained

medium.com

  • Characteristic: a way to handle null references without causing a NullPointerException.
  • Analogy: A substitute teacher. When a teacher isn’t coming to school, the substitute teacher will come to class instead and make sure the kids are well.
  • Biggest Advantage: It can help eliminate null checks in code and provide more seamless and robust handling of null values, reducing the likelihood of runtime errors or unexpected behavior.
  • Headache: Maintain.
  • Use Cases: Any case that makes you want to avoid null checks.
Null object. Source

Repository

Design Patterns in Python: Repository Pattern

The Repository Design Pattern Explained and Implemented in Python

medium.com

  • Characteristic: a layer of abstraction over the data storage
  • Analogy: Purchasing department. A retail store sells different types of products, such as clothes, shoes, and accessories. The store’s inventory is managed by a warehouse located at a different location. The purchasing department interacts with the warehouse to retrieve and store products. The retail store can rely on the Repository to handle all the data storage operations, while the Repository ensures that the data is consistent and properly managed.
  • Biggest Advantage: Separation of concern.
  • Headache: Over-abstraction can increase complexity.
  • Use Cases: Applications that have multiple data sources.
Repository. Source

Unit of Work

Design Patterns in Python: Unit of Work Pattern

The Unit of Work Design Pattern Explained and Implemented in Python

medium.com

  • Characteristic: grouping multiple operations into a single transaction by supporting atomicity.
  • Analogy: a bank transaction will not be completed if any of its component operations fail.
  • Biggest Advantage: consistency.
  • Headache: Managing a large data model can be challenging.
  • Use Cases: It is useful in scenarios where transactional consistency is critical, such as financial transactions, e-commerce applications, and database management systems. It is also helpful in applications where multiple data sources are involved or where complex business logic needs to be implemented.

Leave a Reply

Your email address will not be published. Required fields are marked *