目录
1、单例模式介绍
2、单例代码实现
2.1 static介绍
2.2 C++中static的三种用法:
(1)静态局部变量
(2)静态成员变量
(3)静态成员函数
3、观察者模式介绍
4、观察者代码实现
1、单例模式介绍
单例模式是属于设计模式中的创建型模式分类(将对象的创建和使用相互分离)。
单例模式使用的场景是:在一个进程中,只有一个实例对象。该实例构造函数一般声明为私有类,类外不可访问。通过提供访问实例对象的公共函数来访问该实例对象。
单例模式优点:保证整个程序中只有一个实例类,既保证了数据的唯一性,又节省了空间。
单例的实现方式有:
(1)懒汉式。 (使用时进行实例化。存在线程安全问题)
(2)静态局部变量。 (使用时进行实例化。不存在线程安全问题)
(3)饿汉式。 (单例类创建的时候进行实例化。不存在线程安全问题)
2、单例代码实现
推荐使用静态局部变量实现单例,具体的代码如下:
#include <iostream>class SingletInstance
{
public:static SingletInstance* getInstance(){static SingletInstance ins;return &ins;}
private:SingletInstance(){std::cout << "SingletInstance Constructot " << std::endl;};
};int main()
{std::cout << "this addr is " << SingletInstance::getInstance() << std::endl;std::cout << "this addr is " << SingletInstance::getInstance() << std::endl;return 0;
}
代码运行结果如下:
单例的各种实现方式可参考下面链接:
总结C++单例模式_c++ proto类需要自己释放吗_发如雪Jay的博客-CSDN博客
2.1 static介绍
C++内存分区可大致分为:栈、堆、全局数据区(静态区)、代码区,staitc修饰的内容属的于全局数据区(静态区),全局数据区中存在的变量包括:全局变量和静态变量存储,生成周期在程序结束时释放。
2.2 C++中static的三种用法:
(1)静态局部变量
定义:使用static修饰类型的变量,如static int a。生命周期为程序运行周期。
优点:静态局部变量的作用域外部不可访问,具有较好的安全性。
注意:只初始化一次,若不赋值,则自动赋值为0,下一次进入该函数时,会自动忽略初始化语句。
代码如下:
void func()
{static int a = 10;a++;std::cout << "a " << a << std::endl;
}int main()
{int cnt = 1;while(cnt <= 3){func();cnt++;}return 0;
}
运行结果如下:
(2)静态成员变量
定义:使用static修饰的类成员变量,生命周期为程序运行周期。
注意:每个类的对象的静态成员变量指向的是同一个块地址区域,即数据内容和地址一样。
必须在类对象使用前初始化。
代码如下:
#include <iostream>class A
{
public:static int a;
};int A::a = 10; //必须使用前初始化!
int main()
{std::cout << "A::a is " << A::a <<",addr is " << &(A::a) << std::endl;/ 下面访问静态成员变量的方法不使用,只为了说明,一般使用A::a访问静态成员变量。 //A obj1;A obj2;A obj3;std::cout << "A::a is " << obj1.a << ",addr is " << &(obj1.a) <<std::endl;std::cout << "A::a is " << obj2.a << ",addr is " << &(obj2.a) <<std::endl;std::cout << "A::a is " << obj3.a << ",addr is " << &(obj3.a) <<std::endl;//return 0;
}
运行结果如下:
(3)静态成员函数
定义:在成员函数前面加上static修饰符,如:static void fun(){};
访问:用类名::函数名进行访问
静态成员函数与非静态成员函数区别:非静态成员函数可以任意地访问静态成员函数和静态数据 成员,静态成员函数不能访问非静态成员函数和非静态数据成员。
3、观察者模式介绍
观察者模式属于设计模式中的行为型模式分类(关注对象的行为或者交互方面的内容)。
观察者模式使用场景是 描述多个观察者(Observer)订阅一个被观察者的对象状态;当被观察者状态变化时,被观察者会通知所有订阅的观察者对象,让其接收取到状态变化信息。
应用:Qt框架中数据间的通信机制是信号槽,信号槽机制就是观察者模式_百度百科 (baidu.com)应用的体现。
观察者模式也被称为发布者-订阅模式。观察者模式是对象间一对多的关系描述,类似广播。
4、观察者代码实现
代码设计的观察对象如下:
(1)定义一个抽象的被观察者(AbsTarget)类,该类有订阅、取消订阅、通知属性变化、设置数据的接口。
(2)被观察对象(Target1)继承于AbsTarget,对应的观察者对象有Observer1、Observer2。
(3)被观察对象(Target2)继承于AbsTarget,对应的观察者对象Observer3。
(4) 定义一个抽象的观察者(AbsObserver)类,该类有接收数据变化的接口,该接口为了应对不同的数据类型,接收的数据类型定义为void*。
(5)观察者1(Observer1)继承于AbsObserver类;观察者2(Observer2)继承于AbsObserver类,Observer1和Observer2接收数据变化的数据结构为同一种。
(6)观察者3(Observer3)继承于AbsObserver类,Observer3接收的数据结构为一种。
具体代码实现如下:
#include <iostream>
#include <list>
#include <string>
struct Data1
{int n1;float f1;
};struct Data2
{int n1;std::string strname;
};
//观察者
class AbsObserver
{
public:AbsObserver()=default;virtual ~AbsObserver(){};virtual void receiveData(void* pThis)=0; //使用void*来适应不同的数据类型
};//具体观察者1
class Observer1:public AbsObserver
{
public:Observer1()=default;~Observer1(){};virtual void receiveData(void* pThis)override{Data1* data1 = (Data1*)pThis;std::cout << " Observer1 receive ";std::cout << "f1: " << data1->f1 << ", n1: " <<data1->n1 << std::endl;}
};//具体观察者2
class Observer2:public AbsObserver
{
public:Observer2()=default;~Observer2(){};virtual void receiveData(void* pThis)override{Data1* data1 = (Data1*)pThis;std::cout << " Observer2 receive ";std::cout << "f1: " << data1->f1 << ", n1: " <<data1->n1 << std::endl;}
};class Observer3:public AbsObserver
{
public:Observer3()=default;~Observer3(){};virtual void receiveData(void* pThis)override{Data2* data1 = (Data2*)pThis;std::cout << " Observer3 receive ";std::cout << "strname: " << data1->strname << ", n1: " <<data1->n1 << std::endl;}
};//被观察目标
class AbsTarget{
public:AbsTarget()=default;virtual ~AbsTarget(){std::cout << "~AbsTarget" << std::endl;};virtual void Attach(AbsObserver* obj)=0;virtual void Detach(AbsObserver* obj)=0;virtual void NotifyData()=0;virtual void setData(void* data)=0;};//具体被观察目标类型1
class Target1:public AbsTarget
{
public:Target1()=default;virtual ~Target1(){std::cout << "~Target1" << std::endl;if(m_pObservers.size() >0){m_pObservers.clear();std::cout << "Target1 clear Data" << std::endl;}};virtual void Attach(AbsObserver* obj)override{m_pObservers.push_back(obj);};virtual void Detach(AbsObserver* obj)override{m_pObservers.remove(obj);};virtual void NotifyData()override{for(auto it:m_pObservers){it->receiveData(&m_data1);}}void setData(void* data)override{Data1* tmp = (Data1*)data;m_data1.f1 =tmp->f1;m_data1.n1 =tmp->n1;std::cout << "Target1 NotifyData************" << std::endl;NotifyData();}
private:std::list<AbsObserver*>m_pObservers;Data1 m_data1;
};//具体被观察目标类型2
class Target2:public AbsTarget
{
public:Target2()=default;virtual ~Target2(){std::cout << "~Target2" << std::endl;if(m_pObservers.size() >0){m_pObservers.clear();std::cout << "Target2 clear Data" << std::endl;}};virtual void Attach(AbsObserver* obj)override{m_pObservers.push_back(obj);};virtual void Detach(AbsObserver* obj)override{m_pObservers.remove(obj);};virtual void NotifyData()override{for(auto it:m_pObservers){it->receiveData(&m_data1);}}void setData(void* data)override{Data2* tmp = (Data2*)data;m_data1.strname =tmp->strname;m_data1.n1 =tmp->n1;std::cout << "Target2 NotifyData************" << std::endl;NotifyData();}
private:std::list<AbsObserver*>m_pObservers;Data2 m_data1;
};void UseTarget1()
{AbsTarget *pTarger1 = new Target1();AbsObserver* pObserve1= new Observer1();pTarger1->Attach(pObserve1);AbsObserver* pObserve2= new Observer2();pTarger1->Attach(pObserve2);Data1 tmp;tmp.f1 = 30.06;tmp.n1 = 60;pTarger1->setData(&tmp);pTarger1->Detach(pObserve1);pTarger1->setData(&tmp);pTarger1->Detach(pObserve2);delete pTarger1;pTarger1 = nullptr;delete pObserve1;pObserve1 = nullptr;delete pObserve2;pObserve2 = nullptr;
}void UseTarget2()
{AbsTarget *pTarger2 = new Target2();AbsObserver* pObserve3= new Observer3();pTarger2->Attach(pObserve3);Data2 tmp;tmp.strname = "hello";tmp.n1 = 60;pTarger2->setData(&tmp);pTarger2->Detach(pObserve3);delete pTarger2;pTarger2 = nullptr;delete pObserve3;pObserve3 = nullptr;}
int main()
{std::cout << "*********** Use Target1, Observer1, Observer2 ***********" << std::endl;UseTarget1();std::cout << "\n*********** Use Target2, Observer3 ***********" << std::endl;UseTarget2();return 0;
}
程序运行结果如下:
关于观察者模式介绍也可参考:
C++行为型模式-实现观察者模式_观察者模式c++实现_herryone123的博客-CSDN博客
附加:
1、设计模式介绍和分类可参考:
C++设计模式介绍与分类_夜雨听萧瑟的博客-CSDN博客
2、static的用法可参考:
c++中static的用法详解_c++中static的作用和用法_「已注销」的博客-CSDN博客
对C语言 static作用——修饰 变量(全局变量/局部变量)、函数_c语言static修饰的局部变量_杰儿__er的博客-CSDN博客
3、对信号槽机制感兴趣的可参考链接:
信号槽机制_夜雨听萧瑟的博客-CSDN博客