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

目录

一、装饰器设计模式

1.1 基本知识

1.2 装饰模式的结构与实现

二、观察者设计模式

2.1 基本知识

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


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

第六章:C++之设计模式(一)-CSDN博客icon-default.png?t=N7T8https://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、装饰模式的实现代码

#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、观察者模式的实现代码

//观察者
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; //状态
};

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

//具体博客类
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;
}

相关推荐

  1. C++新经典设计模式22 总结

    2024-06-11 05:18:02       32 阅读
  2. C++新经典设计模式1 介绍

    2024-06-11 05:18:02       20 阅读
  3. C++新经典设计模式2 模板方法模式

    2024-06-11 05:18:02       36 阅读
  4. C++新经典设计模式20 访问者模式

    2024-06-11 05:18:02       28 阅读
  5. C++新经典设计模式19 职责链模式

    2024-06-11 05:18:02       23 阅读
  6. C++新经典设计模式21 解释器模式

    2024-06-11 05:18:02       30 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-11 05:18:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-11 05:18:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-11 05:18:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-11 05:18:02       20 阅读

热门阅读

  1. C++ C_style string overview and basic Input funcitons

    2024-06-11 05:18:02       5 阅读
  2. Helm在线部署Longhorn(1.6.0版本)分布式存储

    2024-06-11 05:18:02       10 阅读
  3. 常用API

    常用API

    2024-06-11 05:18:02      12 阅读
  4. Python图库入门:从基础到进阶的全面解析

    2024-06-11 05:18:02       10 阅读
  5. Ubuntu24.04记录网易邮箱大师的安装

    2024-06-11 05:18:02       10 阅读
  6. 简单介绍Pacstall和 AUR软件管理工具

    2024-06-11 05:18:02       9 阅读