目录
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博客