设计模式(C++)

c++ 23种设计模式【geekband教程】
22种设计模式c++实现
23 种设计模式详解(全23种)
设计模式汇总(C++)【好】
设计模式概述(模式汇总)(C++实现)
C++各类设计模式及实现详解
设计模式(c++)

设计模式–优缺点

设计模式集合【java】
趣味设计模式(github源码)

0、八大设计原则

(1)依赖倒置原则(依赖是指编译时依赖)

高层模块不能依赖低层模块、二者都就依赖于抽象;抽象不能依赖实现细节;实现细节应该依赖抽象。

一、综述

设计模式运用了面向对象编程语言的重要特征:封装、继承、多态等。
宗旨:管理变化,提高复用。即要关注稳定点和变化点。
路径:分解、抽象
手段:继承转组合,包含另一个基类指针。即A类中包含一个B*。
关键:抽象类和接口
重构的技法:静态-》动态,早绑定-》晚绑定,继承-》组合,编译时依赖-》运行时依赖,紧耦合-》松耦合

23种设计模式分为三类:

● 创建型模式,共5种:简单工厂模式(不算入)工厂方法模式抽象工厂模式单例模式建造者模式原型模式
● 结构型模式,共7种:适配器模式装饰器模式代理模式外观模式桥接模式组合模式享元模式
● 行为型模式,共11种:策略模式模板方法模式观察者模式迭代器模式责任链模式命令模式备忘录模式状态模式访问者模式中介者模式解释器模式
● 其他:并发型模式线程池模式
Linux平台下线程池的原理及实现

1、创建型

单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点。
原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
工厂模式(Factory Method):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂模式是一个类的实例化延迟到其子类。
抽象工厂模式(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

2、结构型
桥接模式(Birdge):将抽象部分与它的实现部分分离,使它们都可以独立地变化。
外观模式(Decorator):为子系统中的一组接口提供一个一致的界面,它定义了一个高层接口,这个接口使得这一子系统更加容易使用。
组合模式(Composite):将对象组合成树性结构以表示“部分-整体”的层次关系。它使得客户对单个对象和复合对象的使用具有一致性。
装饰模式(Decorator):动态地给一个对象添加一些额外的职责。就扩展功能而言,装饰模式比生成子类方式更为灵活。如流的扩展操作,既有继承又有组合,继承是为了接口完备,组合是为了多态调用。
适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口。它能够使原本因接口不兼容而不能一起工作的那些类可以一起工作。
代理模式(Proxy):为其他对象提供一个代理以控制对这个对象的访问。
享元模式(Flyweight):运用共享技术有效地支持大量细粒度的对象。

3、行为型
迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。面向对象的迭代器的运行时多态已过时(遍历时虚函数的开销太大),不如模板泛型编程的编译时多态。
解释器模式(Interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
观察者模式(Observer):定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都能通知并自动刷新。如进度通知,通过观察接口,调用具体的观察者的更新虚函数。
中介者模式(Mediator):用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而其耦合松散,而且可以独立地改变它们之间的交互。
访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
备忘录模式(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。
状态模式(State):允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。
策略模式(Strategy):定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。它使得算法的变化可独立于使用它的客户。是if-else模式面向对象式的替换,比如税法计算的扩展,实现多个子类。
模板方法模式(Template Method):定义一个操作中的算法的骨架(Run函数),而将一些步骤延迟到子类中(通过虚函数)。它使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
命令模式(Command):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行修改参数化;对请求排队或记录请求日志,以及支持可取消的操作。不如C++函数对象(能当做函数使用的对象,函数类、lamda匿名函数、std::function类、std::bind和闭包)
职责链模式(Chain of Responsibility):为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象链接成一条链,并沿着这条链传递该请求,直到有一个对象处理它。比如windos窗体消息的处理流程。

二、C++实现

1、工厂模式

大致可以分为三类,简单工厂模式、工厂方法模式、抽象工厂模式。
(1)简单工厂模式
特点:用来生产同一等级结构中的任意产品。需要在工厂类中做判断,从而创造相应的产品。当增加新的产品时,就需要修改工厂类。
缺点:增加新的核类型时,就需要修改工厂类,违反了开放封闭原则。

enum CTYPE {COREA, COREB};     
class SingleCore    
{    
public:    
    virtual void Show() = 0;  
};    
//单核A    
class SingleCoreA: public SingleCore    
{    
public:    
    void Show() { cout<<"SingleCore A"<<endl; }    
};    
//单核B    
class SingleCoreB: public SingleCore    
{    
public:    
    void Show() { cout<<"SingleCore B"<<endl; }    
};  
  
//唯一的工厂,可以生产两种型号的处理器核,在内部判断    
class Factory    
{    
public:     
    SingleCore* CreateSingleCore(enum CTYPE ctype)    
    {    
        if(ctype == COREA) //工厂内部判断    
            return new SingleCoreA(); //生产核A    
        else if(ctype == COREB)    
            return new SingleCoreB(); //生产核B    
        else    
            return NULL;    
    }    
};   

(2)工厂方法模式
特点:用来生产同一等级结构中的固定产品。定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
缺点:每增加一种产品,就需要增加一个对象的工厂。

class SingleCore    
{    
public:    
    virtual void Show() = 0;  
};    
//单核A    
class SingleCoreA: public SingleCore    
{    
public:    
    void Show() { cout<<"SingleCore A"<<endl; }    
};    
//单核B    
class SingleCoreB: public SingleCore    
{    
public:    
    void Show() { cout<<"SingleCore B"<<endl; }    
};    
//工厂的基类里有虚函数,后续继承出各种工厂
class Factory    
{    
public:    
    virtual SingleCore* CreateSingleCore() = 0;  
};    
//生产A核的工厂    
class FactoryA: public Factory    
{    
public:    
    SingleCoreA* CreateSingleCore() { return new SingleCoreA; }    
};    
//生产B核的工厂    
class FactoryB: public Factory    
{    
public:    
    SingleCoreB* CreateSingleCore() { return new SingleCoreB; }    
};   

(3)抽象工厂模式
特点:用来生产不同产品族的全部产品(支持拓展增加产品;支持增加产品族)。提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
缺点:

//单核    
class SingleCore     
{    
public:    
    virtual void Show() = 0;  
};    
class SingleCoreA: public SingleCore      
{    
public:    
    void Show() { cout<<"Single Core A"<<endl; }    
};    
class SingleCoreB :public SingleCore    
{    
public:    
    void Show() { cout<<"Single Core B"<<endl; }    
};    
//多核    
class MultiCore      
{    
public:    
    virtual void Show() = 0;  
};    
class MultiCoreA : public MultiCore      
{    
public:    
    void Show() { cout<<"Multi Core A"<<endl; }    
    
};    
class MultiCoreB : public MultiCore      
{    
public:    
    void Show() { cout<<"Multi Core B"<<endl; }    
};    
//工厂    
class CoreFactory      
{    
public:    
    virtual SingleCore* CreateSingleCore() = 0;  
    virtual MultiCore* CreateMultiCore() = 0;  
};    
//工厂A,专门用来生产A型号的处理器    
class FactoryA :public CoreFactory    
{    
public:    
    SingleCore* CreateSingleCore() { return new SingleCoreA(); }    
    MultiCore* CreateMultiCore() { return new MultiCoreA(); }    
};    
//工厂B,专门用来生产B型号的处理器    
class FactoryB : public CoreFactory    
{    
public:    
    SingleCore* CreateSingleCore() { return new SingleCoreB(); }    
    MultiCore* CreateMultiCore() { return new MultiCoreB(); }    
};   

2、单例模式

(1)预加载
特点:先创建
缺点:线程不安全,因为静态的局部变量是在调用的时候分配到静态存储区,所以在编译的时候没有分配,

class CSingleton    
{    
private:    
    CSingleton()      
    {    
    }    
public:    
    static CSingleton * GetInstance()    
    {    
        static CSingleton instance;     
        return &instance;    
    }    
}; 

改进:

class CMsBsGPSInfoStart
{
public:
	static CMsBsGPSInfoStart& GetInstance();
protected:
 
	CMsBsGPSInfoStart();
	~CMsBsGPSInfoStart();
 
private:
	static CMsBsGPSInfoStart _instance;
private:
	//CLock m_lkMsBsGPSInfoStartFlag;
	bool m_bMsBsGPSInfoStartFlag;    //
 
public:
	bool GetMsBsGPSInfoStart();
	bool SetMsBsGPSInfoStart(bool bIsStart);
};
CMsBsGPSInfoStart CMsBsGPSInfoStart::_instance;
CMsBsGPSInfoStart::CMsBsGPSInfoStart() : m_bMsBsGPSInfoStartFlag(false)
{
	std::cout << "enter CMsBsGPSInfoStart::CMsBsGPSInfoStart() " << endl;
}
 
CMsBsGPSInfoStart::~CMsBsGPSInfoStart()
{
	std::cout << "enter CMsBsGPSInfoStart::~CMsBsGPSInfoStart() " << endl;
}
 
CMsBsGPSInfoStart& CMsBsGPSInfoStart::GetInstance()
{
	std::cout << "CMsBsGPSInfoStart::GetInstance()" << endl;
	return _instance;
}
bool CMsBsGPSInfoStart::SetMsBsGPSInfoStart(bool bIsStart)
{
	m_bMsBsGPSInfoStartFlag = bIsStart;
	return true;
}

(2)懒加载
特点:用时再创建
缺点:线程不安全,要在判断和new的前后加锁

class CSingleton  
{  
public:  
static CSingleton* GetInstance()  
{  
     if ( m_pInstance == NULL )    
         m_pInstance = new CSingleton();  
     return m_pInstance;  
}  
private:  
    CSingleton(){};  
    static CSingleton * m_pInstance;  
};
CSingleton * CSingleton::m_pInstance = NULL;

改进:

//.h
class Singleton  
{
public:  
    static Singleton* getInstance();   
private:      
    Singleton(){} 
    ~Singleton();
    static Singleton* m_instance; 
};  
//.cpp 
CSingleton * CSingleton::m_pInstance = NULL;
Singleton::~Singleton()
{
	if(NULL != m_instance)
	{
		delete m_pInstance;
		m_pInstance = NULL;
	}
}
Singleton* Singleton::getInstance()  
{  
    if(NULL == m_instance)  
    {  
        Lock();//借用其它类来实现,如boost  
        if(NULL == m_instance)  			//双检查,有内存读写reorder漏洞(即“分配内存-构造初始化-返回指针”,变成“分配内存-返回指针-构造初始化”),返回的指针没有初始化,是不可用的
        {  
            m_instance = new Singleton;  
        }  
        UnLock();  
    }  
    return m_instance;  
} 

c++11的用法:

Singleton* Singleton::m_instance;
Singleton* Singleton::getInstance() {    
    static std::once_flag oc;  // 用于call_once的局部静态变量
    std::call_once(oc, [&] {  m_instance = new Singleton();});
    return m_instance;
}

解决reorder问题:

//线程安全的双检查锁 -- C++ 11版本之后的跨平台实现 (volatile)
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
    Singleton* tmp = m_instance.load(std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_acquire);//获取内存fence
    if (tmp == nullptr) {
        std::lock_guard<std::mutex> lock(m_mutex);
        tmp = m_instance.load(std::memory_order_relaxed);
        if (tmp == nullptr) {
            tmp = new Singleton;
            std::atomic_thread_fence(std::memory_order_release);//释放内存fence
            m_instance.store(tmp, std::memory_order_relaxed);
        }
    }
    return tmp;
}

在这里插入图片描述

3、建造者模式

特点:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
缺点:对不同类型的对象需要实现不同的具体构造器的类,这可能回答大大增加类的数量

● Builder中定义了创建Product各个部分的接口(定义构造步骤)。
● ConcreteBuilder中具体实现了创建Product中的各个部分的接口,就是具体的建造者(生产各个组件)。
● Director是根据用户的需求构建Product的(按照步骤组装部件,并返回Product)。

建造者模式和模板方法对比:

建造者模式具体实现的功能与模板方法模式有点类似。比如可以有不同得ConcreteBuilder类实现不同得创建方式。这样从应用上模板方法模式和建造者模式实现的功能是很相似的。但是建造者模式的侧重点是在于Director的不同,可以有不同的呈现方式,而模板方法模式的侧重点是算法中每一步实现的不同。另外,它们的类之间的关系是不同的。模板方法是通过继承的方式来实现的,而建造者模式是通过组合的方式实现的。模板方法模式主要用于执行不同的算法,建造者模式主要用于构建对象。不过者两种模式其实都可以实现很多相似的功能。

建造者模式和工厂模式对比:

生成器模式中,对象构建的过程中需要多个步骤,就像我们例子中的先有主机,再有显示屏,再有鼠标等等,生成器模式的作用就是将这些复杂的构建过程封装起来。
工厂模式构建对象的时候通常就只有一个步骤,调用一个工厂方法就可以生成一个对象。

// BuilderModel.h文件
#pragma once
#include <iostream>
#include <vector>
#include <string>

// 产品类
class Product
{
public:
	void Add(std::string str)
	{
		m_vec.push_back(str);
	}
	void Show()
	{
		for (auto it = m_vec.cbegin(); it != m_vec.cend(); it++)
		{
			std::cout << *it << std::endl;
		}
	}
private:
	std::vector<std::string> m_vec;
};
// 建造者类
class Builder
{
public:
	virtual void BuildPartA() = 0;
	virtual void BuildPartB() = 0;
	virtual void BuildPartC() = 0;
	virtual Product getResult() = 0;
};
//具体建造者类
class ConcreteBuilder_0 : public Builder
{
public:
	ConcreteBuilder_0() : m_p(nullptr)
	{
		m_p = new Product();
	}
	virtual ~ConcreteBuilder_0()
	{
		if (nullptr == m_p)
			delete m_p;
	}
	virtual void BuildPartA()
	{
		std::string str = "Builder_0 BuildPartA";
		m_p->Add(str);
	}
	virtual void BuildPartB()
	{
		std::string str = "Builder_0 BuildPartB";
		m_p->Add(str);
	}
	virtual void BuildPartC()
	{
		std::string str = "Builder_0 BuildPartC";
		m_p->Add(str);
	}
	Product getResult()
	{
		return *m_p;
	}
private:
	Product * m_p;
};

class ConcreteBuilder_1 : public Builder
{
public:
	ConcreteBuilder_1() : m_p(nullptr)
	{
		m_p = new Product();
	}
	virtual ~ConcreteBuilder_1()
	{
		if (nullptr == m_p)
			delete m_p;
	}
	virtual void BuildPartA()
	{
		std::string str = "Builder_1 BuildPartA";
		m_p->Add(str);
	}
	virtual void BuildPartB()
	{
		std::string str = "Builder_1 BuildPartB";
		m_p->Add(str);
	}
	virtual void BuildPartC()
	{
		std::string str = "Builder_1 BuildPartC";
		m_p->Add(str);
	}
	Product getResult()
	{
		return *m_p;
	}
private:
	Product * m_p;
};
// 指挥者类
class Director
{
public:
	// 具体怎么实现根据需求
	void build(Builder *p)
	{
		p->BuildPartA();
		p->BuildPartC();
		p->BuildPartB();
	}
};

测试代码:

#include <iostream>
#include "BuilderModel.h"
int main()
{
	using namespace std;
	// 建造者模式
	Builder *builder= new ConcreteBuilder_0();
	Director * director = new Director();
	director->build(builder);
	builder->getResult().Show();

	delete builder;
	builder = new ConcreteBuilder_1();
	director->build(builder);
	builder->getResult().Show();
	getchar();
	return 0;
}

4、原型模式

当直接创建对象的代价比较大时,则采用这种模式创建重复的对象。对象的构造使用clone成员函数(虚函数),而不是对象的构造函数。
优点:

(1) 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,提高新实例的创建效率。
(2) 扩展性较好,模式中提供了抽象原型类,具体原型类可根据需要扩展。
(3) 原型模式提供了简化的创建结构,模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品。

缺点:

(1) 需要为每一个类配备一个克隆方法,该克隆方法位于一个类的内部,改造已有类时需要修改源代码,违背开闭原则;
(2) 在实现深克隆时需要编写较为复杂的代码,并且如果对象嵌套很多引用时,为了实现深拷贝每一层嵌套都必须支持深克隆。

结构:

● 抽象原型类(AbstractPrototype):规定了具体原型对象必须实现的接口(如果要提供深拷贝,则必须具有实现clone的规定)
●具体原型类(ConcretePrototype):从抽象原型派生而来,是客户程序使用的对象,即被复制的对象,需要实现抽象原型角色所要求的接口。
● 客户端(Client):客户端中声明一个抽象原型类,根据客户需求clone具体原型类对象实例

在这里插入图片描述

// PrototypeModel.h文件
#pragma once
#include <iostream>
#include <string>
// 原型类
class Prototype
{
public:
	virtual Prototype * Clone() = 0;
};
// 
class ConcretePrototype_0 : public Prototype
{
public:
	ConcretePrototype_0(std::string name)
	{
		m_strTypeName = name;
	}
	virtual Prototype * Clone()
	{
		ConcretePrototype_0 *p = new ConcretePrototype_0(m_strTypeName);
		*p = *this;
		return p;
	}
	void Show()
	{
		std::cout << m_strTypeName << std::endl;
	}
private:
	std::string m_strTypeName;
};

class ConcretePrototype_1 : public Prototype
{
public:
	ConcretePrototype_1(std::string name)
	{
		m_strTypeName = name;
	}
	virtual Prototype * Clone()
	{
		ConcretePrototype_1 *p = new ConcretePrototype_1(m_strTypeName);
		*p = *this;
		return p;
	}
	void Show()
	{
		std::cout << m_strTypeName << std::endl;
	}
private:
	std::string m_strTypeName;
};

测试:

#include <iostream>
#include "PrototypeModel.h"

int main()
{
	using namespace std;
	ConcretePrototype_0 * p1 = new ConcretePrototype_0("A");
	ConcretePrototype_1 * p2 = (ConcretePrototype_1 *)(p1->Clone());
	p1->Show();
	p2->Show();
	delete p1;
	delete p2;

	getchar();
	return 0;
}

在这里插入图片描述

// 抽象原型类(AbstractPrototype)
class AbstractPrototypeMail {
public:
    virtual ~AbstractPrototypeMail() = default;
    virtual AbstractPrototypeMail *clone() = 0;
    virtual void showMail() = 0;
    virtual void changeTitle(std::string title) = 0;
    virtual void changeSender(std::string sender) = 0;
    virtual void changeRecipients(std::string rec) = 0;
    virtual void changeBody(std::string body) = 0;
    virtual void changeAtt(std::string name) = 0;
protected:
    AbstractPrototypeMail() = default;
};
// 具体原型类(ConcretePrototype)
class ConcretePrototypeMail : public AbstractPrototypeMail {
public:
    ConcretePrototypeMail(const std::string &title,const std::string &sender,const std::string &rec,const std::string &body, const std::string &nameAtt=""){
        std::cout << "ConcretePrototypeMail Hello" << std::endl;
        mailTitle = title;
        mailSender = sender;
        mailRecipients = rec;
        mailBody = body;
        if (!nameAtt.empty()) {
            mailAtta = new Attachment();
            mailAtta->changeName(nameAtt);
        }
    }
    ~ConcretePrototypeMail() override {
        std::cout << "ConcretePrototypeMail Bye" << std::endl;
        if (mailAtta!= nullptr) {
            delete(mailAtta);
        }
    }
    AbstractPrototypeMail *clone() override {
        auto *newMail = new ConcretePrototypeMail(mailTitle,mailSender,mailRecipients,mailBody,mailAtta->getName());
        return newMail;
    }
    void showMail() override {
        std::cout << "MailTitle: " << mailTitle << std::endl;
        std::cout << "MailSender: " << mailSender << std::endl;
        std::cout << "MailRecipients: " << mailRecipients << std::endl;
        std::cout << "MailBody: " << mailBody << std::endl;
        std::cout << "MailAttachment: " << mailAtta->getName() << std::endl;

    }
    void changeTitle(const std::string title) override {
        mailTitle = title;
    }
    void changeSender(const std::string sender) override {
        mailSender = sender;
    };
    void changeRecipients(const std::string rec) override {
        mailRecipients = rec;
    }
    void changeBody(const std::string body) override {
        mailBody = body;
    }
    void changeAtt(const std::string name) override  {
        if (mailAtta!= nullptr) {
            delete(mailAtta);
        }
        mailAtta = new Attachment();
        mailAtta->changeName(name);
    }

private:
    std::string mailTitle;
    std::string mailSender;
    std::string mailRecipients; /// 按理说 收件人应该有多个 可改为list等其他数据结构,这里采用std::string用于演示
    std::string mailBody;
    Attachment *mailAtta = nullptr;
};   
/// 附件类
class Attachment {
public:
    Attachment() {
        std::cout << "Attachment Hello" << std::endl;
    }
    ~Attachment() {
        std::cout << "Attachment Bye" << std::endl;
    }
    void changeName(const std::string &name) {
        nameAtt = name;
    };
    std::string getName() {
        return nameAtt;
    }
private:
    std::string nameAtt; /// 附件名
};

测试:

//浅拷贝
int main() 
{
    /// 用于复用的初始邮件创建
    auto *originalMail = new ConcretePrototypeMail("original_title","original_sender","original_rec","original_body","original_attachment");
    std::cout << "originalMail address: "<< originalMail << std::endl;
    originalMail->showMail();
    /// 浅拷贝
    std::cout << "====浅拷贝====" << std::endl;
    auto *copyMail_A = originalMail;
    copyMail_A->changeTitle("copymail_title");
    copyMail_A->changeSender("copymail_sender");
    copyMail_A->changeRecipients("copymail_rec");
    copyMail_A->changeBody("copymail_body");
    copyMail_A->changeAtt("copymail_attachment");
    std::cout << "====copyMail_A====" << std::endl;
    std::cout << "copyMail_A address: "<< copyMail_A << std::endl;
    copyMail_A->showMail();
    std::cout << "====originalMail====" << std::endl;
    originalMail->showMail();
    delete originalMail;
    return 0;
}
//深拷贝
int main() 
{
    /// 用于复用的初始邮件创建
    auto *originalMail = new ConcretePrototypeMail("original_title","original_sender","original_rec","original_body");
    originalMail->changeAtt("original_attachment"); 
    std::cout << "originalMail address: "<< originalMail << std::endl;
    originalMail->showMail();
    /// 深拷贝
    std::cout << "====深拷贝====" << std::endl;
    auto *copyMail_A = originalMail->clone();
    copyMail_A->changeTitle("copymail_title");
    copyMail_A->changeSender("copymail_sender");
    copyMail_A->changeRecipients("copymail_rec");
    copyMail_A->changeBody("copymail_body");
    copyMail_A->changeAtt("copymail_attachment");
    std::cout << "====copyMail_A====" << std::endl;
    std::cout << "copyMail_A address: "<< copyMail_A << std::endl;
    copyMail_A->showMail();
    std::cout << "====originalMail====" << std::endl;
    originalMail->showMail();
    delete originalMail;
    delete copyMail_A;
    return 0;
}

5、观察者模式(推)和监听者模式(拉)

observer、listener模式的推与拉
观察者模式(推模型+拉模型)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值