【C++】单例模式和观察者模式

单例模式(创建型)

创建型模式:提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象

确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例

比如日志模块,数据库模块,任务管理器

饿汉式单例模式

  • 还没有获取实例对象,实例对象就已经产生了,饿汉式是线程安全的
  • 优点:程序加载时就进行实例化,之后的操作效率会很高。
  • 缺点: 由于程序加载时就进行实例化,如果后续不对此类进行任何操作,就会导致内存的浪费
//饿汉式单例:没调用获取单例对象的接口,单例对象就已经产生了
class Singleton
{
public:
    static Singleton* getInstance()					//3 定义获取唯一实例的接口方法
    {
        return &instance;
	}
private:
    static Singleton instance;						//2 定义一个唯一的类的实例对象
private:
    Singleton() {}						 			//1 构造函数私有化
    Singleton(const Singleton&) = delete;			//1 删除拷贝构造
    Singleton& operator=(const Singleton&) = delete;//1 删除赋值重载
    
};
Singleton Singleton::instance;  //类的static成员要在类外初始化,不赋初值则为编译器默认值

static成员要在类外初始化。为什么?

因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的。

懒汉式单例模式

  • 直到第一次获取唯一实例的时候,才产生实例
  • 优点: 在第一次调用的时候才进行实例化。
  • 缺点: 当多个线程同时进入到 if(instance == nullptr) {…} 时,会创建多个对象。
//懒汉式单例,将对象的实例化延迟到第一次调用的时候
class Singleton
{
public:
    static Singleton* getInstance()					//3 定义获取唯一实例的接口方法
    {
        if(instance == nullptr)
        {
            instance = new Singleton();
        }
        return instance;
	}
private:
    static Singleton *instance;						//2 定义一个唯一的类的实例对象
private:
    Singleton() {}						 			//1 构造函数私有化
    Singleton(const Singleton&) = delete;			//1 删除拷贝构造
    Singleton& operator=(const Singleton&) = delete;//1 删除赋值重载
    
};
Singleton* Singleton::instance = nullptr;  

加互斥量,保证getInstance多线程环境是安全的

//线程安全的懒汉式单例

std::mutex mtx;//*****

class Singleton
{
public:
    static Singleton* getInstance()				
    {
        if(instance == nullptr)
        {
            lock_guard<std::mutex> guard(mtx);//*****锁加双重判断,锁放这是让锁粒度小一点
            if(instance == nullptr)
            {
                instance = new Singleton();
			}  
        }
        return instance;
	}
private:
    static Singleton *volatile instance;  //volatile告诉编译器instance是要每次在内存中读取的,不要优化到去缓存中读取
private:
    Singleton() {}						 		
    Singleton(const Singleton&) = delete;		
    Singleton& operator=(const Singleton&) = delete;
    
};
Singleton*volatile Singleton::instance = nullptr;  

懒汉式单例代码2:

//线程安全的懒汉式单例

std::mutex mtx;//*****

class Singleton
{
public:
    static Singleton* getInstance()				
    {
        //线程安全的,函数静态局部变量的初始化,在汇编指令上已经自动添加线程互斥指令了
        static Singleton instance;
		return &instance;
	}
private:
    Singleton() {}						 		
    Singleton(const Singleton&) = delete;		
    Singleton& operator=(const Singleton&) = delete;
};

观察者模式(行为型)

行为型模式主要关注的是对象之间的通信

观察者模式别名:发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式

主要关注的是对象的一对多的关系,也就是多个对象都依赖一个对象,当该对象的状态发生改变时,其他对象都能够接收到相应的通知

例如:通过一组数据(数据对象)可以绘制曲线图(对象1)、柱状图(对象2)、圆饼图(对象3),当数据对象发生改变时,对象123都要及时收到通知,图形上做出相应的改变

Observer1,Observer2,Observer3

Subject(主题)有更改,应该及时通知相应的观察者,去处理相应的事件

#include <iostream>
#include <unordered_map>
#include <list>
using namespace std;

//观察者抽象类
class Observer 
{
public:
	//处理消息的接口
	virtual void handle(int msgid) = 0;  
};

//第1个观察者实例
class Observer1 : public Observer
{
public:
	void handle(int msgid)
	{
		switch (msgid)
		{
		case 1:
			cout << "Observer1 recv msg1!" << endl;
			break;
		default:
			cout << "Observer1 recv unknown msg!" << endl;
			break;
		}
	}
};

//第2个观察者实例
class Observer2 : public Observer
{
public:
	void handle(int msgid)
	{
		switch (msgid)
		{
		case 2:
			cout << "Observer2 recv msg2!" << endl;
			break;
		default:
			cout << "Observer2 recv unknown msg!" << endl;
			break;
		}
	}
};

//第3个观察者实例
class Observer3 : public Observer
{
public:
	void handle(int msgid)
	{
		switch (msgid)
		{
		case 3:
			cout << "Observer3 recv msg3!" << endl;
			break;
		default:
			cout << "Observer3 recv unknown msg!" << endl;
			break;
		}
	}
};

//主题类
class Subject
{
public:
	//往容器中注册/添加观察者
	void addObserver(Observer* obser, int msgid)  
	{
		_subMap[msgid].push_back(obser);  //往msgid对应的观察者链表中插入obser,这句等价于下面注释中的
		/*auto it = _subMap.find(msgid);
		if (it != _subMap.end())
		{
			it->second.push_back(obser);
		}
		else
		{
			list<Observer*> lis;
			lis.push_back(obser);
			_subMap.insert({ msgid, lis });
		}*/
	}

	//通知观察者
	void dispatch(int msgid)
	{
		auto it = _subMap.find(msgid);
		if (it != _subMap.end())
		{
			for (Observer* pObser : it->second)  //遍历list
			{
				pObser->handle(msgid);
			}
		}
		else
		{
			cout << "没有观察者对该消息感兴趣" << endl;
		}
	}
private:
	unordered_map<int, list<Observer*>> _subMap;//msgid - 对该msgid感兴趣的观察者们
};

int main()
{
	Subject subject;
	Observer *p1 = new Observer1();
	Observer *p2 = new Observer2();
	Observer *p3 = new Observer3();

	subject.addObserver(p1, 1);
	subject.addObserver(p2, 2);
	subject.addObserver(p3, 3);

	int msgid = 0;
	while (1)
	{
		cout << "消息id:" ;
		cin >> msgid;
		if (msgid == -1)
			break;
		subject.dispatch(msgid);
	}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值