YouTip LogoYouTip

Python Design Pattern Intro

Design patterns are **reusable solutions** to common problems in software development. They are not complete designs that can be directly translated into code, but rather **templates or blueprints** for solving specific problems.\\\\n\\\\n### Core Value of Design Patterns\\\\n\\\\nDesign patterns are like standard blueprints in the field of architecture, providing the following benefits for software development:\\\\n\\\\n* **Improve code reusability**: Avoid reinventing the wheel\\\\n* **Enhance code maintainability**: Make code structure clearer\\\\n* **Promote team collaboration**: Provide a unified programming language and way of thinking\\\\n* **Improve code quality**: Proven solutions are more reliable\\\\n\\\\n### Real-life Analogy of Design Patterns\\\\n\\\\nImagine you want to build a house:\\\\n\\\\n* **Original approach**: Design from scratch every time, which is error-prone and inefficient\\\\n* **Using design patterns**: Use standard architectural blueprints, knowing the standard layout for the living room, kitchen, and bedrooms\\\\n\\\\nDesign patterns are the "standard architectural blueprints" of software development.\\\\n\\\\nAccording to the classic book **"Design Patterns - Elements of Reusable Object-Oriented Software"**, there are 23 classic design patterns. These patterns can be divided into three major categories based on their focus: Creational Patterns, Structural Patterns, and Behavioral Patterns. In addition, in enterprise-level development, there is another category of commonly used architectural design patterns.\\\\n\\\\n| No. | Pattern & Description | Includes |\\\\n| --- | --- | --- |\\\\n| 1 | **Creational Patterns** are used to solve object creation problems. By encapsulating instantiation logic and hiding specific implementation details, they make the system more flexible and scalable when creating objects. | * Factory Pattern * Abstract Factory Pattern * Singleton Pattern * Builder Pattern * Prototype Pattern |\\\\n| 2 | **Structural Patterns** focus on the composition and collaboration of classes and objects, helping us build flexible, reusable, and scalable system structures. | * Adapter Pattern * Bridge Pattern * Filter / Criteria Pattern * Composite Pattern * Decorator Pattern * Facade Pattern * Flyweight Pattern * Proxy Pattern |\\\\n| 3 | **Behavioral Patterns** focus on communication and responsibility allocation between objects. By encapsulating algorithms, states, or request logic, they enhance the flexibility and maintainability of the system. | * Chain of Responsibility Pattern * Command Pattern * Interpreter Pattern * Iterator Pattern * Mediator Pattern * Memento Pattern * Observer Pattern * State Pattern * Null Object Pattern * Strategy Pattern * Template Method Pattern * Visitor Pattern |\\\\n| 4 | **Enterprise Architectural Patterns** These patterns are commonly used in the layered architecture of large systems, focusing on the collaboration between the presentation layer and the business logic layer. | * MVC Pattern (Model-View-Controller Pattern) * Business Delegate Pattern * Composite Entity Pattern * Data Access Object Pattern * Front Controller Pattern * Intercepting Filter Pattern * Service Locator Pattern * Transfer Object Pattern |\\\\n\\\\nThe image below shows the relationships and hierarchical structure among various design patterns:\\\\n\\\\n![Image 1: Relationships between design patterns](#)\\\\n\\\\n* Provide a unified design language, enabling developers to quickly communicate design intent.\\\\n* Provide mature, reusable solutions for common problems.\\\\n* Reduce system coupling, and improve code maintainability and scalability.\\\\n* Reduce repetitive design, enhancing development efficiency and code quality.\\\\n* Help new members quickly understand system architecture and design concepts.\\\\n\\\\n**1. Open-Closed Principle**\\\\n\\\\nOpen for extension, closed for modification. Software should be able to adapt to changes by extending new functionality rather than modifying existing code. The core of implementing this principle lies in using abstractions (interfaces or base classes) to define stable behaviors.\\\\n\\\\n**2. Liskov Substitution Principle**\\\\n\\\\nAnywhere a base class appears, a subclass should be able to replace it. Inheritance only makes sense when a derived class can completely replace its base class. This principle ensures the correctness of polymorphism and is an important supplement to the Open-Closed Principle.\\\\n\\\\n**3. Dependency Inversion Principle**\\\\n\\\\nHigh-level modules should not depend on low-level modules; both should depend on abstractions. Specific implementations should depend on interfaces or abstract classes, rather than directly on concrete classes. This principle makes the system easier to extend and test.\\\\n\\\\n**4. Interface Segregation Principle**\\\\n\\\\nA class should not depend on interfaces it does not need. Large interfaces should be split into smaller, more specialized interfaces to reduce coupling and improve flexibility.\\\\n\\\\n**5. Law of Demeter**\\\\n\\\\nAlso known as the "Principle of Least Knowledge": an object should minimize its interactions with other objects. In other words, a class should only know about objects directly related to itself, thereby reducing system complexity.\\\\n\\\\n**6. Composite Reuse Principle**\\\\n\\\\nPrefer using composition or aggregation relationships to achieve reuse rather than inheritance. Inheritance creates strong coupling, whereas composition allows for flexible replacement of dependencies at runtime, resulting in a more elegant structural design.\\\\n\\\\n* * *\\\\n\\\\n## Common Design Pattern Examples in Python\\\\n\\\\nLet's understand the application of design patterns in Python through a few specific examples.\\\\n\\\\n### Singleton Pattern\\\\n\\\\nThe Singleton pattern ensures that a class has only one instance and provides a global access point to it.\\\\n\\\\n## Instance\\\\n\\\\nclass DatabaseConnection:\\\\n\\\\n _instance =None\\\\n\\\\ndef __new__ (cls):\\\\n\\\\nif cls._instance is None:\\\\n\\\\n cls._instance =super(). __new__ (cls)\\\\n\\\\nprint("Create a new database connection")\\\\n\\\\nreturn cls._instance\\\\n\\\\ndef connect(self):\\\\n\\\\nprint("Connect to the database")\\\\n\\\\n# UseExample\\\\n\\\\n db1 = DatabaseConnection()\\\\n\\\\n db2 = DatabaseConnection()\\\\n\\\\nprint(f"db1 and db2 Is it the same instance?{db1 is db2}")# Output: True\\\\n\\\\n**Application Scenarios**:\\\\n\\\\n* Database connection pools\\\\n* Configuration managers\\\\n* Loggers\\\\n\\\\n### Factory Pattern\\\\n\\\\nThe Factory pattern provides an interface for creating objects, letting subclasses decide which class to instantiate.\\\\n\\\\n## Instance\\\\n\\\\nfrom abc import ABC, abstractmethod\\\\n\\\\n# Abstract Product\\\\n\\\\nclass Notification(ABC):\\\\n\\\\n@abstractmethod\\\\n\\\\ndef send(self, message: str):\\\\n\\\\npass\\\\n\\\\n# Concrete Product\\\\n\\\\nclass EmailNotification(Notification):\\\\n\\\\ndef send(self, message: str):\\\\n\\\\nprint(f"Send email:{message}")\\\\n\\\\nclass SMSNotification(Notification):\\\\n\\\\ndef send(self, message: str):\\\\n\\\\nprint(f"Send SMS:{message}")\\\\n\\\\n# Factory class\\\\n\\\\nclass NotificationFactory:\\\\n\\\\n@staticmethod\\\\n\\\\ndef create_notification(notification_type: str) -> Notification:\\\\n\\\\nif notification_type =="email":\\\\n\\\\nreturn EmailNotification()\\\\n\\\\nelif notification_type =="sms":\\\\n\\\\nreturn SMSNotification()\\\\n\\\\nelse:\\\\n\\\\nraise ValueError("Unsupported notification type")\\\\n\\\\n# UseExample\\\\n\\\\nemail= NotificationFactory.create_notification("email")\\\\n\\\\n sms = NotificationFactory.create_notification("sms")\\\\n\\\\nemail.send("Your order has been shipped")\\\\n\\\\n sms.send("Verification code: 123456")\\\\n\\\\n**Code Explanation**:\\\\n\\\\n* `Notification` is the abstract base class that defines the interface\\\\n* `EmailNotification` and `SMSNotification` are concrete implementations\\\\n* `NotificationFactory` is responsible for creating specific notification objects\\\\n\\\\n### Observer Pattern\\\\n\\\\nThe Observer pattern defines a one-to-many dependency between objects. When the state of one object changes, all objects that depend on it will be notified.\\\\n\\\\n## Instance\\\\n\\\\nfrom abc import ABC, abstractmethod\\\\n\\\\n# Observer interface\\\\n\\\\nclass Observer(ABC):\\\\n\\\\n@abstractmethod\\\\n\\\\ndef update(self, message: str):\\\\n\\\\npass\\\\n\\\\n# Concrete observer\\\\n\\\\nclass EmailSubscriber(Observer):\\\\n\\\\ndef __init__ (self, name: str):\\\\n\\\\nself.name= name\\\\n\\\\ndef update(self, message: str):\\\\n\\\\nprint(f"{self.name} Received email notification:{message}")\\\\n\\\\nclass SMSSubscriber(Observer):\\\\n\\\\ndef __init__ (self, name: str):\\\\n\\\\nself.name= name\\\\n\\\\ndef update(self, message: str):\\\\n\\\\nprint(f"{self.name} Received SMS notification:{message}")\\\\n\\\\n# Subject (Observable)\\\\n\\\\nclass NewsPublisher:\\\\n\\\\ndef __init__ (self):\\\\n\\\\nself._subscribers =[]\\\\n\\\\ndef subscribe(self, subscriber: Observer):\\\\n\\\\nself._subscribers.append(subscriber)\\\\n\\\\ndef unsubscribe(self, subscriber: Observer):\\\\n\\\\nself._subscribers.remove(subscriber)\\\\n\\\\ndef notify_subscribers(self, message: str):\\\\n\\\\nfor subscriber in self._subscribers:\\\\n\\\\n subscriber.update(message)\\\\n\\\\n# UseExample\\\\n\\\\n publisher = NewsPublisher()\\\\n\\\\n# Create subscribers\\\\n\\\\n alice = EmailSubscriber("Alice")\\\\n\\\\n bob = SMSSubscriber("Bob")\\\\n\\\\n# Subscribe to news\\\\n\\\\n publisher.subscribe(alice)\\\\n\\\\n publisher.subscribe(bob)\\\\n\\\\n# Publish news\\\\n\\\\n publisher.notify_subscribers("Python 3.12 Published!")\\\\n\\\\n# Unsubscribe\\\\n\\\\n publisher.unsubscribe(alice)\\\\n\\\\n publisher.notify_subscribers("This is a notification only Bob can see.")\\\\n\\\\n* * *\\\\n\\\\n## Special Considerations for Design Patterns in Python\\\\n\\\\n### Python's Dynamic Nature\\\\n\\\\nAs a dynamic language, some design patterns are simpler to implement in Python:\\\\n\\\\n## Instance\\\\n\\\\n# Python Simple Factory style\\\\n\\\\ndef create_payment(method):\\\\n\\\\n payment_methods ={\\\\n\\\\n'credit_card': CreditCardPayment,\\\\n\\\\n'paypal': PayPalPayment,\\\\n\\\\n'alipay': AlipayPayment\\\\n\\\\n}\\\\n\\\\nreturn payment_methods()\\\\n\\\\n# Use directly, without complex class hierarchies\\\\n\\\\n payment = create_payment('alipay')\\\\n\\\\n### Built-in Support for the Decorator Pattern\\\\n\\\\nPython has built-in decorator syntax, making the implementation of the Decorator pattern more elegant:\\\\n\\\\n## Instance\\\\n\\\\ndef log_execution_time(func):\\\\n\\\\ndef wrapper(*args, **kwargs):\\\\n\\\\nimport time\\\\n\\\\n start =time.time()\\\\n\\\\n result = func(*args, **kwargs)\\\\n\\\\n end =time.time()\\\\n\\\\nprint(f"{func.__name__} Execution time:{end - start:.2f}Second")\\\\n\\\\nreturn result\\\\n\\\\nreturn wrapper\\\\n\\\\n@log_execution_time\\\\n\\\\ndef process_data(data):\\\\n\\\\n# Simulate data processing\\\\n\\\\nimport time\\\\n\\\\ntime.sleep(1)\\\\n\\\\nreturn f"Processed data:{data}"\\\\n\\\\n# Use\\\\n\\\\n result = process_data("Exampledata")
← Python SingletonReact Intro β†’