• 设计模式(c++)


    开闭原则

    开闭原则(Open/Closed Principle)指出软件实体(类、模块、函数等)应该对扩展开放,但对修改关闭

    合成复用原则

    组合大于继承

    设计模式

    设计模式通常分为三种主要类型:创建型设计模式、结构型设计模式和行为型设计模式

    1. 常见的创建型设计模式包括:

      1. 单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。
        用于控制资源的访问,如数据库连接或文件系统。

      2. 工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。常用于将对象创建的逻辑从应用逻辑中分离出来。

      3. 抽象工厂模式(Abstract Factory):提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。适用于系统需要处理多系列产品,但希望客户端无需关心具体实现的情况。

      4. 建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。通常用于创建复杂对象,允许用户按步骤指定复杂对象的各个部分,在用户代码中隔离复杂对象的创建和组装过程。

      5. 原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
        适用于创建重复对象时,效率更高的场景。

    2. 常见的结构型设计模式包括:

      1. 适配器模式(Adapter):允许将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
      2. 装饰器模式(Decorator):动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活。
      3. 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
      4. 桥接模式(Bridge):将抽象部分与实现部分分离,使它们都可以独立地变化。
      5. 外观模式(Facade):为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
      6. 组合模式(Composite):将对象组合成树形结构以表示“部分-整体”的层次结构,组合使得用户对单个对象和组合对象的使用具有一致性。
    3. 常见的行为型设计模式包括:

      1. 策略模式(Strategy):允许在运行时选择算法的行为。
      2. 观察者模式(Observer):当一个对象状态改变时,所有依赖于它的对象都会得到通知并被自动更新。
      3. 命令模式(Command):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。
      4. 责任链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
      5. 状态模式(State):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
      6. 模板方法模式(Template Method):在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中实现。

    单例模式 (Singleton)

    https://zhuanlan.zhihu.com/p/37469260

    • 保证一个类仅有一个实例,并提供一个访问它的全局访问点
    • 相比于全局变量,单例模式可以延迟初始化,在使用前不会被创建,全局变量通常在启动时立即初始化

    用法示例:

    • 定义一个单例类 私有化它的构造函数
    • 使用类的私有静态指针变量指向类的唯一实例;
    • 使用一个公有的静态方法获取该实例。

    懒汉版(Lazy Singleton)代码示例

    // 单例实例在第一次被使用时才进行初始化
    class Singleton
    {
    private:
    	static Singleton* instance;
    private:
    	Singleton() {};
    	~Singleton() {};
    	Singleton(const Singleton&);
    	Singleton& operator=(const Singleton&);
    public:
    	static Singleton* getInstance() 
        {
    		if(instance == NULL) 
    			instance = new Singleton();
    		return instance;
    	}
    };
    
    // init static member
    Singleton* Singleton::instance = NULL;
    

    Meyers’ Singleton 代码示例

    // C++0x之后该实现是线程安全的
    class Singleton
    {
    private:
    	Singleton() { };
    	~Singleton() { };
    	Singleton(const Singleton&);
    	Singleton& operator=(const Singleton&);
    public:
    	static Singleton& getInstance() 
        {
    		static Singleton instance;
    		return instance;
    	}
    };
    

    饿汉版(Eager Singleton)代码示例

    // 单例实例在程序运行时被立即执行初始化
    class Singleton
    {
    private:
    	static Singleton instance;
    private:
    	Singleton();
    	~Singleton();
    	Singleton(const Singleton&);
    	Singleton& operator=(const Singleton&);
    public:
    	static Singleton& getInstance() {
    		return instance;
    	}
    }
    
    // initialize defaultly
    Singleton Singleton::instance;
    

    工厂方法模式(Factory Method)

    • 封装创建逻辑(解耦、可重用、一致性和可维护性)
    • 返回一个抽象类型的指针或接口,从而使得客户代码可以无需知道具体的产品类,只依赖于产品的接口或基类(多态)
    • 相比于简单工厂模式(一个工厂方法,根据接受的参数不同,而创建不同的产品实例),工厂方法模式符合开闭原则,即无需修改原有的工厂类和方法,只需增加新的产品类和对应的工厂类,(灵活性、可扩展性)

    用法示例

    • 定义抽象产品类Product
    • 定义A产品类ProductA 继承自Product
    • 定义B产品类ProductB 继承自Product
    • 定义抽象工厂类Creator
    • 定义A产品工厂类CreatorA
    • 定义B产品工厂类CreatorB
    • 创建X产品工厂类的实例 用于生成相应产品类的实例(均返回抽象类型Product的指针)

    代码示例

    #include 
    #include 
    
    class Product {
    public:
        virtual void operation() = 0;
    };
    
    class ConcreteProductA : public Product {
    public:
        void operation() override {
            std::cout << "Operation of ConcreteProductA" << std::endl;
        }
    };
    
    class ConcreteProductB : public Product {
    public:
        void operation() override {
            std::cout << "Operation of ConcreteProductB" << std::endl;
        }
    };
    
    class Creator {
    public:
        virtual Product* factoryMethod() = 0;
    };
    
    class ConcreteCreatorA : public Creator {
    public:
        Product* factoryMethod() override {
            return new ConcreteProductA();
        }
    };
    
    class ConcreteCreatorB : public Creator {
    public:
        Product* factoryFactyoryMethod() override {
            return new ConcreteProductB();
        }
    };
    
    // 使用示例
    int main() {
        std::unique_ptr<Creator> creatorA(new ConcreteCreatorA());
        std::unique_ptr<Product> productA(creatorA->factoryMethod());
        productA->operation();
        
        std::unique_ptr<Creator> creatorB(new ConcreteCreatorB());
        std::unique_ptr<Product> productB(creatorB->factoryMethod());
        productB->operation();
    
    	Creator* creater = new ConcreteCreatorX();	
    	Product* product = creater->factoryMethod();	// 多态
    	product->operation();							// 多态
        
        return 0;
    }
    

    适配器模式 (Adapter)

    • 将不兼容的对象包装起来使其能够与其他类协同工作
    • 将一个类的接口转换成另一个期望的接口
    • 分为类适配器和对象适配器
      • 类适配器使用继承(特别是多重继承)来实现适配:
        • 优点:可以重写部分被适配者(Adaptee)的行为。
        • 缺点:因为继承了被适配者,所以耦合度较高。
      • 对象适配器使用组合来实现适配
        • 优点:更加灵活,减少了类之间的耦合度。
        • 缺点:需要额外的指针来访问被适配者。

    用法示例

    • 类适配器:公有继承新接口(虚基类),私有继承旧接口,重写新接口中的方法(调用旧接口方法)
    • 对象适配器:公有继承新接口,拥有一个旧接口对象的引用,重写新接口中的方法(调用旧接口对象的成员方法)

    代码示例

    class OldRectangle {
    public:
        void draw() {
            std::cout << "Old Rectangle draw method." << std::endl;
        }
    };
    
    class NewShape {
    public:
        virtual void display() = 0;
        virtual ~NewShape() {}
    };
    
    // 类适配器
    class RectangleAdapter : public NewShape, private OldRectangle {
    public:
        void display() override {
            // 调用 OldRectangle 的 draw 方法
            draw();
        }
    };
    
    // 对象适配器
    class RectangleAdapter : public NewShape {
    private:
        OldRectangle* oldRectangle;  // 持有一个对旧接口类的引用
    
    public:
        RectangleAdapter(OldRectangle* rectangle) : oldRectangle(rectangle) {}
    
        void display() override {
            // 调用 OldRectangle 的 draw 方法
            oldRectangle->draw();
        }
    
        ~RectangleAdapter() {
            delete oldRectangle;
        }
    };
    
    int main() {
        OldRectangle* oldRectangle = new OldRectangle();
        NewShape* rectangleAdapter = new RectangleAdapter(oldRectangle);
        rectangleAdapter->display();
    
        delete rectangleAdapter;  // 注意:这将正确地释放适配器和旧的矩形对象
        return 0;
    }
    
    

    外观模式 (Facade)

    • 提供了一个统一的接口来访问子系统中的一组接口,来简化系统接口,减少用户对子系统的耦合
    • 不符合开闭原则

    用法示例

    • 定义一个外观类,拥有其他类对象作为成员,其函数成员的实现为:一组对其他对象成员函数的调用

    代码示例

    class MultimediaSystemFacade {
    private:
        AudioPlayer audioPlayer;
        VideoPlayer videoPlayer;
        Broadcaster broadcaster;
    
    public:
        void playMultimedia() {
            audioPlayer.playAudio();
            videoPlayer.playVideo();
        }
    
        void sendMessage(const std::string& message) {
            broadcaster.broadcastMessage(message);
        }
    };
    

    代理模式(Proxy)

    • 提供一个代替对象(代理对象)来控制对原对象的访问。通常用于延迟处理操作、控制访问、提供智能指引等功能
    • 广泛应用于网络服务、内存中的大对象管理、安全控制等多种场景中
    • 主要有三种类型:
      • 虚拟代理:在需要时才创建开销很大的对象。
      • 保护代理:控制对原始对象的访问,用于对象应有不同的访问权限时。
      • 智能引用代理:当调用对象的特定方法时,执行一些附加操作,如计数对象引用次数、记录日志等。

    用法示例

    • 定义一个代理类,拥有被代理类对象作为成员,通过代理类调用被代理类的方法,从而在调用前添加额外的控制,实现延迟处理操作、控制访问、提供智能指引等

    桥接模式(Bridge)

    • 提供一个桥接结构,将抽象层和实现层解耦,从而简化了复杂系统的类结构
    • 一维扩展用继承/组合,多维扩展(品牌与产品)用桥接

    用法示例

    • Abstraction (抽象类):定义抽象类的接口,它包含一个指向 Implementor 类型对象的引用。
    • RefinedAbstraction (扩充抽象类):扩展 Abstraction 定义的接口。
    • Implementor (实现类接口):定义实现类的接口,这些类具体实现基本操作,但在 Abstraction 中以抽象方式提供。
    • ConcreteImplementor (具体实现类):Implementor 接口的具体实现。

    例如:用于不同类型设备(如电视、无线投影仪等)的遥控器应用,每种设备都有不同的实现,但控制接口相似(开/关、调节音量等)

    • 抽象 (Abstraction)
      抽象部分由 RemoteControl 类及其扩展类 AdvancedRemoteControl 表示。这个抽象层定义了高层和通用的操作逻辑,如切换电源 (togglePower)、调节音量 (volumeUp, volumeDown) 以及静音操作 (mute)。
      • RemoteControl (基本遥控): 提供了基础的遥控功能。
      • AdvancedRemoteControl (高级遥控): 在基本遥控的基础上增加了额外的功能,例如静音。
    • 实现 (Implementor)
      实现部分由 Device 接口及其具体实现类 TV 和 Radio 表示。这个层面处理关于设备的具体操作细节,如设备的开关状态和音量控制具体是如何执行的。
      • Device (设备接口): 定义了操作设备必须实现的方法,例如 enable(), disable(), getVolume(),
        setVolume()。
      • TV (电视): 实现了Device接口,提供了电视特有的操作方式。
      • Radio (收音机): 同样实现了Device接口,按照收音机的方式执行操作。
    • 桥接连接
      RemoteControl (抽象) 持有一个到 Device (实现) 的引用。这个引用允许抽象层通过实现层提供的接口与具体的设备进行交互,而不需要关心这些设备的具体实现细节。这就是所谓的“桥接”,即抽象层和实现层之间通过组合而非继承来建立联系,从而使得两者可以独立地变化。

    装饰器模式(包装模式)(Decorator)

    • 动态地给一个对象添加一些额外的职责或功能,也是继承关系的一种代替方案(合成复用原则:组合大于继承),它通过组合而非继承增加功能,从而避免了由于继承引入的静态特性

    用法示例

    • 定义装饰器类,维持一个指向被装饰类对象的引用,实现被装饰类的接口,另外添加新的功能

    模版方法模式(Template Method)

    • 定义了一个操作中的算法的框架,将一些步骤的实现延迟到子类,允许子类在不改变算法结构的情况下重新定义算法的某些特定步骤
    • 封装不变部分,扩展可变部分;提取公共代码,便于维护;行为由父类控制,子类实现

    用法示例

    1. 定义抽象类,设置算法框架,实现固定部分,声明由子类实现的抽象操作。
    2. 定义继承自抽象类的具体类,实现抽象类中定义的抽象方法和钩子(hook)

    代码示例

    // 抽象类
    class Beverage {
    public:
        // 模板方法,定义算法框架
        void prepareRecipe() {
            boilWater();
            brew();           // 特定于子类的步骤
            pourInCup();
            addCondiments();  // 特定于子类的步骤
        }
    protected:
        virtual void brew() = 0;         // 由子类实现
        virtual void addCondiments() = 0;// 由子类实现
        void boilWater() {std::cout << "Boiling water" << std::endl;}
        void pourInCup() {std::cout << "Pouring into cup" << std::endl;}
        virtual ~Beverage() {}
    };
    
    // 具体类:咖啡
    class Coffee : public Beverage {
    protected:
        void brew() override {std::cout << "Dripping Coffee through filter" << std::endl;}
        void addCondiments() override {std::cout << "Adding Sugar and Milk" << std::endl;}
    };
    
    // 具体类:茶
    class Tea : public Beverage {
    protected:
        void brew() override {std::cout << "Steeping the tea" << std::endl;}
        void addCondiments() override {std::cout << "Adding Lemon" << std::endl;}
    };
    

    策略模式(Strategy)

    • 定义了一组算法,他们可以以相同的接口共享。在根据不同的条件选择不同的行为时,可以使用此模式进行解耦,使代码更易于维护和扩展
    • 使算法独立于使用他们的客户而独立变化。(在有多种算法相似的情况下,避免使用if…else所带来的复杂和难以维护)。

    用法示例

    1. 定义抽象策略类,提供公共接口
    2. 定义继承自抽象策略类的具体策略类,提供具体算法实现
    3. 定义上下文类,其中维护一个对策略类对象的引用,用于设定策略,执行策略

    观察者模式(Observer)

    • 定义了对象之间的一对多依赖关系,当一个对象改变状态时,所有依赖于它的对象都会得到通知并自动更新
    • 常用于实现分布式事件处理系统、在应用中实现跨系统的消息交换等场景

    用法示例

    • Subject(主题):也称为“被观察者”,维护一份观察者列表,并提供用于增加或删除观察者的方法。
    • Observer(观察者):为那些在主题状态发生改变时需获得通知的对象定义一个更新接口。
    • ConcreteSubject(具体主题):状态变化时,向 Observer 发送通知,存储 Observer 对象关心的数据。
    • ConcreteObserver(具体观察者):实现 Observer 的更新接口以使自身状态与主题的状态相协调。

    代码示例

    // Observer interface
    class Observer {
    public:
        virtual void update(float price) = 0;
        virtual ~Observer() {}
    };
    
    // Subject interface
    class Subject {
    public:
        virtual void registerObserver(Observer* observer) = 0;
        virtual void removeObserver(Observer* observer) = 0;
        virtual void notifyObservers() = 0;
        virtual ~Subject() {}
    };
    
    class Stock : public Subject {
    private:
        std::list<Observer*> observers;
        float price;
    public:
        // Register an observer
        void registerObserver(Observer* observer) override {observers.push_back(observer);}
        // Remove an observer
        void removeObserver(Observer* observer) override {observers.remove(observer);}
        // Notify all registered observers
        void notifyObservers() override {
            for (auto& observer : observers) {
                observer->update(price);
            }
        }
        // Method to update price
        void setPrice(float newPrice) {price = newPrice; notifyObservers();}
    };
    
    class PriceDisplay : public Observer {
    private:
        float price;
    public:
        void update(float newPrice) override {price = newPrice; display();}
        void display() const {std::cout << "Current Stock Price: $" << price << std::endl;}
    };
    
    int main() {
        Stock stock;                           // Create a Stock object which is the subject.
        PriceDisplay display;                  // Create an observer.
    
        stock.registerObserver(&display);      // Register the observer with the subject.
        
        stock.setPrice(150.0f);                // Change the stock price, triggers notifications.
        stock.setPrice(155.5f);                // Change the stock price again.
    
        stock.removeObserver(&display);        // Unregister the observer.
        stock.setPrice(160.0f);                // No notification this time.
    
        return 0;
    }
    

    责任链模式(Chain of Responsibility)

    • 将请求的发送者和接收者解耦
    • 多个对象都有机会处理请求,将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

    用法示例

    1. 定义处理者基类,拥有一个基类对象的引用(下一个处理者),提供处理请求的接口,提供设置下一个处理者的接口。
    2. 定义派生自基类的具体处理者类,实现处理请求的接口:处理它所负责的请求,如果可以处理就处理,不能处理就将请求转发给链上的下一个对象。

    代码示例

    #include 
    #include 
    
    // Handler
    class Approver {
    protected:
        Approver* successor = nullptr;
    public:
        void setSuccessor(Approver* successor) {this->successor = successor;}
        virtual void processRequest(int amount) = 0;
        virtual ~Approver() {}
    };
    
    // ConcreteHandler1
    class Manager : public Approver {
    public:
        void processRequest(int amount) override {
            if (amount < 1000) {
                std::cout << "Manager will approve $" << amount << std::endl;
            } else if (successor) {
                successor->processRequest(amount);
            }
        }
    };
    
    // ConcreteHandler2
    class Director : public Approver {
    public:
        void processRequest(int amount) override {
            if (amount < 5000) {
                std::cout << "Director will approve $" << amount << std::endl;
            } else if (successor) {
                successor->processRequest(amount);
            }
        }
    };
    
    // ConcreteHandler3
    class CEO : public Approver {
    public:
        void processRequest(int amount) override {
            if (amount < 20000) {
                std::cout << "CEO will approve $" << amount << std::endl;
            } else {
                std::cout << "Request $" << amount << " needs further meeting!" << std::endl;
            }
        }
    };
    
    int main() {
        Manager manager;
        Director director;
        CEO ceo;
    
        // Set up the chain
        manager.setSuccessor(&director);
        director.setSuccessor(&ceo);
    
        // Various requests
        manager.processRequest(500);   // Manager handles this request
        manager.processRequest(1500);  // Director handles this request
        manager.processRequest(7000);  // CEO handles this request
        manager.processRequest(50000); // Needs further meeting
        
        return 0;
    }
    
  • 相关阅读:
    新能源分布式资产上链 数字新云南启航
    SQL语句的常用函数介绍
    科学家绘制全球140多万个湖泊和水库的水下地形图
    用于生成makefile文件sh脚本
    Part7:Pandas 的SettingWithCopyWarning 报警复现、原因、解决方案
    【VPX611】基于6U VPX总线架构的SATA3.0高性能数据存储板(3.2GByte/s存储带宽)
    手机厂商“卷”到了手腕上
    软考网络工程师华为配置考点总结
    Leecode 周赛318场
    k8s安装遇到过的一些问题
  • 原文地址:https://blog.csdn.net/ysy10599105/article/details/139651733