单例模式是一种对象创建型的设计模式,使用单例模式,可以保证一个类只生成唯一的实例对象。也就是说,在整个程序中,该类只存在一个实例对象。
构造函数私有化
提供一个全局的静态方法,访问唯一的对象
类中定义一个静态的指针,指向唯一的对象
类图如下,两个公有属性,然后把构造函数私有化就可以了
在应用系统开发过程中,如果有以下四个需求通常都可以采用单例模式:
1.需要生成唯一序列的环境
2.需要频繁实例化然后销毁的对象
3.创建对象时耗时过多或者消耗资源过多,但又经常用到的对象
4.方便资源相互通信的环境
实际案例:
多线程中网络资源初始化(网络资源共享,可以采用单例设计模式的方式去设计)
回收站机制
任务管理器(如果怎么打开任务管理器 / 回收站,永远都只会出现一个窗口)
应用程序日志管理(保证读写方式能够每次都进行一个追加模式去做一个日志操作)
... ...
懒汉式:直接在静态方法中构造对象,不在外面创建对象
#include
using namespace std;
class SingleTon
{
public:
static SingleTon* m_singleTon; //提供一个静态指针
static SingleTon* GetInstance() //添加一个静态属性的方法给类外做访问
{
if (m_singleTon == NULL) //首先判断对象是否存在 如果不存在就创建
{
m_singleTon = new SingleTon; //对象在函数中创建
}
return m_singleTon; //如果对象存在就没必要创建 直接返回就可以了
}
void TestPrint()
{
cout << "测试调用....." << endl;
}
private:
SingleTon() //构造函数私有化,类外无法创建对象
{
cout << "构造对象......" << endl;
m_singleTon = NULL; //给静态指针做初始化
}
};
SingleTon* SingleTon::m_singleTon = NULL; //静态方法在类外初始化 使用类名限定 在类外不创建对象
int main()
{
//构造函数私有化 类外不能创建对象 但是可以创建指针 通过类名限定调用
SingleTon* p1 = SingleTon::GetInstance();
//两个指针指向同一个对象
SingleTon* p2 = SingleTon::GetInstance();
//用 16 进制打印 p1 和 p2 的地址 指向的是同一个对象
cout << "p1:" << hex << p1 << endl;
cout << "p2:" << hex << p2 << endl;
p1->TestPrint();
p2->TestPrint();
return 0;
}
/* 输出 */
构造对象......
p1:000001E1FCBCD050
p2:000001E1FCBCD050
测试调用.....
测试调用.....
饿汉式:在外面直接构造对象,<不在静态方法中构造对象,直接返回>
由于饿汉式得方式是全局变量,在多线程当中可能会产生资源竞争的问题,需要自己做资源的调整或者加锁的过程
#include
using namespace std;
class SingleTon
{
public:
static SingleTon* m_singleTon; //静态指针
static SingleTon* GetInstance() //提供静态方法
{
//if (m_singleTon == NULL)
//{
// m_singleTon = new SingleTon;
//}
return m_singleTon;
}
void TestPrint()
{
cout << "测试调用....." << endl;
}
private:
SingleTon() //构造函数私有化
{
cout << "构造对象......" << endl;
m_singleTon = NULL;
}
};
//用对象指针直接 new 一个对象 无论是否使用 反正对象都是存在的
SingleTon* SingleTon::m_singleTon = new SingleTon;
int main()
{
SingleTon* p1 = SingleTon::GetInstance();
SingleTon* p2 = SingleTon::GetInstance();
cout << "p1:" << hex << p1 << endl;
cout << "p2:" << hex << p2 << endl;
//简单调用
p1->TestPrint();
p2->TestPrint();
return 0;
}
优点
在内存当中只有一个对象,节省内存空间
避免频繁地创建销毁对象,可以提高性能
避免对共享资源的多重占用,简化访问
为整个系统提供一个全局访问点
做游戏的过程中可以使用单例设计模式对资源进行把控,所有的资源用一个类去描述,所有的模块当中如果需要用到资源,就用同一个对象的属性
缺点
不适用于变化频繁的对象 / 经常做拷贝操作的对象
如果实例化的对象长时间未使用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失
简单工厂模式属于类的创建型的设计模式,又叫做静态工厂方法模式。
通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
减少客户程序对类创建过程的依赖
1.提供一个工厂类:负责实现创建所有实例的内部逻辑。可被外界直接调用,创建所需的产品对象。
2.提供一个抽象产品类:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口,所有产品公共的父类。
3.提供一个具体产品类:简单工厂模式所创建的具体实例对象,产品是怎么实现的?继承抽象类去实现产品
类图如下,实际产品继承抽象产品类
如果自己去实现加减乘除,自己写类的话,可能很多人比如我可能直接就写在一个类里面了,如果用简单工厂的设计模式去实现去写的话,就需要去设计这么多类的实现
如果要有其他的运算符例如 %,还是需要去修改原来的工厂类代码,这是简单工厂模式的弊端,不适合我们去做拓展,违背了开放封闭原则
c++纯虚函数(特殊的虚函数)和ADT过程(抽象数据类型)_小雪菜本菜的博客-CSDN博客
#include
using namespace std;
/*
简单计算器: + - * /
1.提供一个工厂类: 提供运算方式 产生不同产品
2.提供一个抽象产品类: 运算符类 + 提供接口负责运算得到结果
3.提供一个具体产品类: 具体运算符类:加法类、减法类、乘法类、除法类...
*/
//抽象一个产品类
class Operation
{
public:
//这里采用产品的公有属性<一般写私有属性减少与类外的联系>
//左值
double m_leftValue;
//右值
double m_rightValue;
//由于是抽象类 提供一个纯虚函数
virtual double GetResult() = 0;
};
//具体产品继承抽象产品类
//加 产品 1
class AddOperation :public Operation
{
double GetResult()
{
//左值加右值
return m_leftValue + m_rightValue;
}
};
//减 产品 2
class SubOperation :public Operation
{
double GetResult()
{
return m_leftValue - m_rightValue;
}
};
//乘 产品 3
class MulOperation :public Operation
{
double GetResult()
{
return m_leftValue * m_rightValue;
}
};
//除 产品 4
class DivOperation :public Operation
{
double GetResult()
{
//暂时不考虑除数为 0 的情况
return m_leftValue / m_rightValue;
}
};
//工厂类负责整个产品的创建
class OperatorFatory
{
public:
//用静态方法判定需要什么产品 返回产品的父类指针用字符表示运算符的类型 用子类对象初始化父类指针
static Operation* createOperation(char c)
{
//针对运算符做不同的对象创建
switch (c)
{
case '+':
//返回加法的对象
return new AddOperation;
break;
case '-':
//...
return new SubOperation;
break;
case '*':
return new MulOperation;
break;
case '/':
return new DivOperation;
break;
}
/* warning C4715: “OperatorFatory::createOperation”: 不是所有的控件路径都返回值 */
return NULL;
}
};
int main()
{
//传入加法创建加法的产品 通过 OperatorFatory 工厂来创建一个对象
Operation* add = OperatorFatory::createOperation('+');
//初始化左值和右值
add->m_leftValue = 1;
add->m_rightValue = 2;
//打印结果
cout << add->GetResult() << endl;
//如果需要不同的产品就创建不同的对象 接下来创建一个减法
add = OperatorFatory::createOperation('-');
//一般情况会把数据放在构造函数中初始化 每次产品创建好后都要做初始化
add->m_leftValue = 3;
add->m_rightValue = 4;
cout << add->GetResult() << endl;
return 0;
}
/* 输出 */
3
-1
优点
帮助封装
实现组件封装,面向(工厂类的接口)接口编程
解耦合
客户端和具体实现类的解耦合(继承产品类是解耦合的一个过程,把抽象产品类和具体产品做了一个分离过程,类似依赖倒置原则)
缺点
可能增加客户端的复杂度
不方便扩展子工厂(如果有新的工程,要修改原代码并且实现新的类)