第六章:C++之设计模式(二)

目录

一、装饰器设计模式

[1.1 基本知识](#1.1 基本知识)

[1.2 装饰模式的结构与实现](#1.2 装饰模式的结构与实现)

二、观察者设计模式

[2.1 基本知识](#2.1 基本知识)

[2.2 观察者模式的结构与实现](#2.2 观察者模式的结构与实现)


上一节我们介绍了C++常用的两种设计模式:单例设计模式、工厂设计模式。本节继续对其余两种设计模式:装饰器设计模式、观察者设计模式进行介绍。

第六章:C++之设计模式(一)-CSDN博客https://blog.csdn.net/L_peanut/article/details/139354881?spm=1001.2014.3001.5501

一、装饰器设计模式

1.1 基本知识

定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

优点:(1)装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用;(2)通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果;(3)装饰器模式完全遵守开闭原则。

缺点:装饰模式会增加许多子类,过度使用会增加程序得复杂性。

1.2 装饰模式的结构与实现

通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。下面来分析其基本结构和实现方法。

1、装饰模式主要包含的角色

(1)抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。

(2)具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。

(3)抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。

(4)具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

2、装饰模式的结构图

3、装饰模式的实现代码

cpp 复制代码
#include <string>
#include <iostream>

//基础组件接口定义了可以被装饰器修改的操作
class Component {
public:
    virtual ~Component() {}
    virtual std::string Operation() const = 0;
};

//具体组件提供了操作的默认实现。这些类在程序中可能会有几个变体。
class ConcreteComponent : public Component {
public:
    std::string Operation() const override {
        return "ConcreteComponent";
    }
};

//装饰器基类和其他组件遵循相同的接口。这个类的主要目的是为所有的具体装饰器定义封装接口。
//封装的默认实现代码中可能会包含一个保存被封装组件的成员变量,并且负责对齐进行初始化。
class Decorator : public Component {
protected:
    Component* component_;

public:
    Decorator(Component* component) : component_(component) {
    }

    //装饰器会将所有的工作分派给被封装的组件
    std::string Operation() const override {
        return this->component_->Operation();
    }
};

//具体装饰器必须在被封装对象上调用方法,不过也可以自行在结果中添加一些内容。
class ConcreteDecoratorA : public Decorator {
//装饰器可以调用父类的是实现,来替代直接调用组件方法。
public:
    ConcreteDecoratorA(Component* component) : Decorator(component) {
    }
    std::string Operation() const override {
        return "ConcreteDecoratorA(" + Decorator::Operation() + ")";
    }
};

//装饰器可以在调用封装的组件对象的方法前后执行自己的方法
class ConcreteDecoratorB : public Decorator {
public:
    ConcreteDecoratorB(Component* component) : Decorator(component) {
    }
    std::string Operation() const override {
        return "ConcreteDecoratorB(" + Decorator::Operation() + ")";
    }
};

//客户端代码可以使用组件接口来操作所有的具体对象。这种方式可以使客户端和具体的实现类脱耦
void ClientCode(Component* component) {
    // ...
    std::cout << "RESULT: " << component->Operation();
    // ...
}


int main() {
    Component* simple = new ConcreteComponent;
    std::cout << "Client: I've got a simple component:\n";
    ClientCode(simple);
    std::cout << "\n\n";

    Component* decorator1 = new ConcreteDecoratorA(simple);
    Component* decorator2 = new ConcreteDecoratorB(decorator1);
    std::cout << "Client: Now I've got a decorated component:\n";
    ClientCode(decorator2);
    std::cout << "\n";

    delete simple;
    delete decorator1;
    delete decorator2;
    return 0;
}

二、观察者设计模式

2.1 基本知识

定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

优点:(1)降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。(2)目标与观察者之间建立了一套触发机制。

缺点:(1)目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。 (2)当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

2.2 观察者模式的结构与实现

1、装饰模式主要包含的角色

(1)抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和 增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。

(2)具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当 具体主题的内部状态发生改变时,通知所有注册过的观察者对象。

(3)抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方 法,当接到具体主题的更改通知时被调用。

(4)具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到 目标的更改通知时更新自身的状态。

可以举个博客订阅的例子,当博主发表新文章的时候,即博主状态发生了改变,那些订阅的读者就会收到通知,然后进行相应的动作,比如去看文章,或者收藏起来。博主与读者之间存在种一对多的依赖关系。

2、观察者模式的结构图

可以看到博客类中有一个观察者链表(即订阅者),当博客的状态发生变化时,通过Notify成员函数通知所有的观察者,告诉他们博客的状态更新了。而观察者通过Update成员函数获取博客的状态信息。

3、观察者模式的实现代码

cpp 复制代码
//观察者
class Observer
{
public:
    Observer() {}
    virtual ~Observer() {}
    virtual void Update() {}
};

//博客
class Blog
{
public:
    Blog() {}
    virtual ~Blog() {}
    void Attach(Observer *observer) { m_observers.push_back(observer); } //添
加观察者
    void Remove(Observer *observer) { m_observers.remove(observer); } //移
除观察者
    void Notify() //通知观察者
    {
        list<Observer*>::iterator iter = m_observers.begin();
        for(; iter != m_observers.end(); iter++)
            (*iter)->Update();
    }
    virtual void SetStatus(string s) { m_status = s; } //设置状态
    virtual string GetStatus() { return m_status; } //获得状态
private:
    list<Observer* > m_observers; //观察者链表
protected:
    string m_status; //状态
};

以上是观察者和博客的基类,定义了通用接口。博客类主要完成观察者的添加、移除、通知操作,设置和获得状态仅仅是一个默认实现。下面给出它们相应的子类实现。

cpp 复制代码
//具体博客类
class BlogCSDN : public Blog
{
private:
    string m_name; //博主名称
public:
    BlogCSDN(string name): m_name(name) {}
    ~BlogCSDN() {}
    void SetStatus(string s) { m_status = "CSDN通知 : " + m_name + s; } //具体设置
状态信息
    string GetStatus() { return m_status; }
    };

//具体观察者
class ObserverBlog : public Observer
{
private:
    string m_name; //观察者名称
    Blog *m_blog; //观察的博客,当然以链表形式更好,就可以观察多个博客
public:
    ObserverBlog(string name,Blog *blog): m_name(name), m_blog(blog) {}
    ~ObserverBlog() {}
    void Update() //获得更新状态
    {
        string status = m_blog->GetStatus();
        cout<<m_name<<"-------"<<status<<endl;
    }
};


//测试案例
int main()
{
    Blog *blog = new BlogCSDN("wuzhekai1985");
    Observer *observer1 = new ObserverBlog("tutupig", blog);
    blog->Attach(observer1);
    blog->SetStatus("发表C++之设计模式(二)");
    blog->Notify();
    delete blog; delete observer1;
    return 0;
}
相关推荐
DogDaoDao24 分钟前
leetcode 面试经典 150 题:矩阵置零
数据结构·c++·leetcode·面试·矩阵·二维数组·矩阵置零
抓哇FullStack-Junior41 分钟前
设计模式——适配器模式
java·设计模式·适配器模式
计科土狗2 小时前
前缀和与差分
c++·算法
时清云2 小时前
【算法】 课程表
前端·算法·面试
silver6872 小时前
桥接模式详解
设计模式
思忖小下3 小时前
梳理你的思路(从OOP到架构设计)_设计模式Observer模式
观察者模式·设计模式·eit
午言若3 小时前
MYSQL 架构
c++·mysql
绝无仅有5 小时前
PHP语言laravel框架中基于Redis的异步队列使用实践与原理
后端·面试·架构
羑悻的小杀马特5 小时前
【AIGC篇】畅谈游戏开发设计中AIGC所发挥的不可或缺的作用
c++·人工智能·aigc·游戏开发
闻缺陷则喜何志丹5 小时前
【C++动态规划】1105. 填充书架|2104
c++·算法·动态规划·力扣·高度·最小·书架