Application scenarios of design patterns in modern software development


The application of design patterns in modern software development

introduction

Design patterns are an excellent practice in software engineering for solving common problems in software design. Design patterns not only provide a standard programming practice, but also help improve the readability, maintainability and scalability of the code. This article will introduce various commonly used design patterns in detail and conduct in-depth analysis based on actual application scenarios.

“Design patterns are the building blocks of elegant, maintainable code.” — Robert C. Martin, “Clean Code”

creational pattern

Singleton Pattern

The singleton pattern is used to ensure that a class has only one instance and provides a global access point. This is useful in scenarios such as logging systems, resource managers, thread pools, and memory pools.

// C++ 单例模式实现
class Singleton {
    
    
public:
    static Singleton& getInstance() {
    
    
        static Singleton instance;
        return instance;
    }
private:
    Singleton() {
    
    }
};

Factory Pattern

The factory pattern is used to create objects, which encapsulates the object's construction process. This model is applied in the compiler of the open source project NVDLA and the pass in LLVM.

// C++ 工厂模式实现
class Factory {
    
    
public:
    static Product* createProduct(string type) {
    
    
        if (type == "A") return new ProductA();
        if (type == "B") return new ProductB();
        return nullptr;
    }
};

structural pattern

Adapter Pattern

Adapter mode is used to connect two incompatible interfaces. The container adapters stack and queue in STL are excellent use cases for object adapters.

// C++ 适配器模式实现
class Adapter : public Target, private Adaptee {
    
    
public:
    void request() override {
    
    
        specificRequest();
    }
};

Proxy Pattern

The proxy pattern is used to provide a proxy for an object to control access to the original object. C++'s smart pointers and reference counting are applications of the proxy pattern.

// C++ 代理模式实现
class Proxy : public Subject {
    
    
public:
    void request() override {
    
    
        realSubject.request();
    }
private:
    RealSubject realSubject;
};

behavioral patterns

Observer Pattern

The Observer pattern is used to establish a one-to-many dependency relationship. When the state of an object changes, all objects that depend on it will be notified. Qt's signal and slot mechanism is an application of the observer pattern.

// C++ 观察者模式实现
class Observer {
    
    
public:
    virtual void update(int value) = 0;
};

Strategy Pattern

Strategy pattern is used to define a series of algorithms and encapsulate each algorithm so that they can be replaced with each other.

// C++ 策略模式实现
class Strategy {
    
    
public:
    virtual void algorithm() = 0;
};

Application scenarios of design patterns

• Singleton mode: logging system, resource manager, thread pool, memory pool, etc.
• Factory mode: encapsulation of created objects, in line with the opening and closing principle. The factory pattern is widely used in many projects because it encapsulates the construction process of objects and makes the interface for creating objects unified and concise. On the other hand, it conforms to the opening and closing principle and is easy to expand. The establishment of various nodes in the compiler of the open source project NVDLA and the pass in LLVM all have factory mode use cases.
• Adapter pattern: The container adapter stack and queue in STL are excellent use cases for object adapters. It is also often used in project development.
• Observer pattern: Frequently used, the observer pattern establishes a one-to-many linkage. When one object changes, it will automatically notify other objects, and other objects will respond. Message update, broadcast mechanism, message delivery, chain triggering...such as Qt's signal and slot mechanism
• Chain of responsibility model: Decouple the sender and receiver of a request, allowing multiple objects to have the opportunity to process the request. Connect the objects that receive the request into a chain, and pass the request along this chain until an object can handle it. Using the chain of responsibility model not only facilitates expansion (when adding a recipient, you only need to insert the corresponding processing method at the appropriate position in the chain), but also replaces the switch-case or if-else that may exist in the code. The chain of responsibility pattern can be applied in the design of tools and task processing scenarios with hierarchical relationships or authority relationships.
• Strategy pattern: Often paired with the factory pattern to encapsulate different algorithms (strategies), combined with the C++ polymorphic mechanism, the strategy pattern is widely used in the actual development process.
• Proxy mode: C++ smart pointers, reference counting, etc.
• Composite mode: GUI

Builder Pattern : Used to separate the steps of creating complex objects so that the same building process can create different representations. For example, create a complex document, build a complex meal, etc.

Prototype Pattern : used to create clones of objects. The prototype pattern can be used when the creation cost of the object is high, or the object has a lot of shared state. For example, the implementation of prototype chain in JavaScript.

Bridge Pattern : Separates abstraction from its implementation so that they can change independently. For example, the interface between the driver and the device, or different database drivers.

Decorator Pattern : Allows adding new functionality to an existing object without changing its structure. For example, Java's I/O stream, decoration of GUI components, etc.

Flyweight Pattern : Used to reduce the number of objects created to reduce memory usage and improve performance. For example, small object cache, string pool, etc.

Template Method Pattern : Define the skeleton of an algorithm in a method, but defer some steps to subclasses. Subclasses can redefine certain steps without changing the structure of the algorithm. For example, common steps for database connection, common steps for algorithms, etc.

Command Pattern : Encapsulates the request as an object, allowing users to use different requests, queue requests, or record request logs, while supporting reversible operations. For example, GUI buttons and menu items, undo and redo functions, etc.

Mediator Pattern : Reduce direct communication between objects and make them rely on a mediating object for communication. For example, chat rooms, communication between aircraft towers and aircraft, etc.

Memento Pattern : Capture the internal state of an object and save this state outside the object without destroying the encapsulation. This way, you can later restore the object to its original saved state. For example, undo functions, save game state, etc.

Visitor Pattern : Add new operations without modifying existing classes. For example, compiler syntax tree traversal, report generation, etc.

Summarize

Design patterns are important tools in software development because they provide elegant ways to solve common problems. By using design patterns, we can not only improve code quality, but also improve development efficiency.

“Programs must be written for people to read, and only incidentally for machines to execute.” — Harold Abelson and Gerald Jay Sussman, “Structure and Interpretation of Computer Programs”

Design patterns are not only the art of programming, but also the art of thinking. They reflect the universal ways in which people solve problems and organize complex systems.

I hope this article helps you better understand and apply design patterns.

“正如Bjarne Stroustrup在《The C++ Programming Language》中所说:‘The most important single aspect of software development is to be clear about what you are trying to build.’”

In our programming learning journey, understanding is an important step for us to move to a higher level. However, mastering new skills and ideas always requires time and persistence. From a psychological point of view, learning is often accompanied by constant trial and error and adjustment, which is like our brain gradually optimizing its "algorithm" for solving problems.

This is why when we encounter mistakes, we should view them as opportunities to learn and improve, not just as annoyances. By understanding and solving these problems, we can not only fix the current code, but also improve our programming skills and prevent making the same mistakes in future projects.

I encourage everyone to actively participate and continuously improve their programming skills. Whether you are a beginner or an experienced developer, I hope my blog will be helpful on your learning journey. If you find this article useful, you may wish to click to bookmark it, or leave your comments to share your insights and experiences. You are also welcome to make suggestions and questions about the content of my blog. Every like, comment, share and attention is the greatest support for me and the motivation for me to continue sharing and creating.


Read my CSDN homepage and unlock more exciting content: Bubble’s CSDN homepage
Insert image description here

Guess you like

Origin blog.csdn.net/qq_21438461/article/details/132928245