05 原型模式

概念
原型模式:
使用原型实例指定带创建对象的类型,并且通过复制这个原型实例创建型的对象
三大角色
- 抽象原型类(AbstractPrototype):声明克隆clone自身的接口;
- 具体圆形类(ConcretePrototype):实现clone接口;
- 客户端(Client):客户端中声明一个抽象原型类,根据客户需求clone具体原型类对象实例。
克隆方法
将对象包含的所有属性都创建一份拷贝,但会产生两种拷贝结果:
- 浅拷贝:如果原型对象的成员使值类型(int,double,char等),将复制一份给拷贝对象;如果原型对象的成员变量是指针/引用,则将指针/引用指向的地址拷贝一份给拷贝对象,即原型对象和拷贝对象中的成员变量指向同一地址。
- 深拷贝:无论原型对象中的成员变量是值类型还是指针/引用类型,都将复制一份给拷贝对象。
优点:
- 当创建新的对象实例较为复杂时,原型模式可以简化创建过程,提高创建对象的频率;
- 可扩展:模式中提供了抽象原型类,具体原型类可适当扩展;
- 创建结构简单:创建工厂即为原型对象本身。
缺点:
- 深复制代码较为复杂;
- 每一个类都得配备一个clone方法,且该方法位于类内部,修改违背了开闭原则
适用环境:
- 当创建新的对象实例较为复杂时,原型模式可以简化创建过程;
- 结合优点第三条,需要避免适用分层的工厂来创建分层的对象,并且类的实例对象只有一个或很少几个的组合状态,通过复制原型对象得到新的实例,比通过适用构造函数创建一个新的实例会更加方便。
PrototypePattern.h
#ifndef __PROTOTYPE_PATTERN__
#define __PROTOTYPE_PATTERN__
#include <iostream>
#include <string>
using namespace std;
//work model类
class WorkModel
{
public:
string modelName;
void setWorkModelName(string iName) {
this->modelName = iName;
}
};
//抽象原型类PrototypeWork
class PrototypeWork
{
public:
PrototypeWork() {}
virtual PrototypeWork *clone() = 0;
private:
};
//具体原型类ConcreteWork
class ConcreteWork :public PrototypeWork
{
public:
ConcreteWork() {}
ConcreteWork(string iName, int iIdNum, string modelName) {
this->name = iName;
this->idNum = iIdNum;
this->workModel = new WorkModel();
this->workModel->setWorkModelName(modelName);
}
// 实现深复制
ConcreteWork *clone() {
ConcreteWork *work = new ConcreteWork();
work->setName(this->name);
work->setIdNum(this->idNum);
work->workModel = this->workModel;
return work;
}
void setName(string iName) {
this->name = iName;
}
void setIdNum(int iIdNum) {
this->idNum = iIdNum;
}
void setModel(WorkModel *iWorkModel) {
this->workModel = iWorkModel;
}
//打印work信息
void printWorkInfo() {
cout << this->name << endl;
cout << this->idNum << endl;
cout << this->workModel->modelName << endl;
}
private:
string name;
int idNum;
WorkModel *workModel;
};
#endif //__PROTOTYPE_PATTERN__
PrototypePattern.cpp
#include "PrototypePattern.h"
int main()
{
#if 0
ConcreteWork *sevenWork = new ConcreteWork("seven", 1001, "seven_model");
cout << "seven的作业:" << endl;
sevenWork->printWorkInfo();
cout << "li直接抄作业......" << endl;
// 浅复制
ConcreteWork *liWork = sevenWork;
cout << "li的作业:" << endl;
liWork->printWorkInfo();
// 抄完作业得改名字和学号
cout << "li改作业的名字和学号......" << endl;
liWork->setName("li");
liWork->setIdNum(1002);
WorkModel *liMode = new WorkModel();
liMode->setWorkModelName("li_model");
liWork->setModel(liMode);
// 检查是不是改对了
cout << "seven的作业:" << endl;
sevenWork->printWorkInfo();
cout << "li的作业" << endl;
liWork->printWorkInfo();
#endif
ConcreteWork *sevenWork = new ConcreteWork("seven", 1001, "seven_model");
cout << "seven的作业:" << endl;
// 深复制
ConcreteWork *liWork = sevenWork->clone();
cout << "li的作业" << endl;
// 抄完作业改名字和学号
cout << "抄完作业改名字和学号......" << endl;
liWork->setName("li");
liWork->setIdNum(1002);
WorkModel *liModel = new WorkModel();
liModel->setWorkModelName("li_model");
liWork->setModel(liModel);
// 检查是否改对了
cout << "seven的作业:" << endl;
sevenWork->printWorkInfo();
cout << "li的作业:" << endl;
liWork->printWorkInfo();
system("pause");
return 0;
}
06 单例模式
概念
单例模式:
确保一个类只有以一个实例,并提供一个全局访问点来访问这个唯一的实例。
三要点
- 这个类只能有一个实例
- 它必须自己创建这个实例
- 它必须自己向整个系统提供这个实例
可以看出,单例模式中,构造函数是私有的(private),即单例模式对象只能在类内部实例化,只能自己创建实例(满足单例模式第2个要点);同时,实例对象是静态的(static),满足第1点只有一个实例;第3个要点即外界如何获取这个单例对象:通过静态方法
static getInstance()获取。
优点:
- 单例模式提供了严格的对唯一实例的创建和访问
- 单例模式的实现可以节省系统资源
缺点:
- 如果某个实例负责多重职责但又必须实例唯一,那单例类的职责过多,这违背了单一职责原则
- 多线程下需要考虑线程安全机制
- 单例模式没有抽象层,不方便扩展
适用环境:
- 系统只需要一个实例对象
- 某个实例只允许有一个访问接口
SingletonPattern.h
#ifndef __SINGLETON_PATTERN__
#define __SINGLETON_PATTERN__
#include <iostream>
#include <string.h>
using namespace std;
// 抽象产品类AbstractBall
class Singleton {
public:
static Singleton *getInstance() {
if (instance == NULL) {
cout << "创建新实例" << endl;
instance = new Singleton();
}
return instance;
}
private:
Singleton() {}
static Singleton *instance;
};
Singleton *Singleton::instance = NULL;
#endif __SINGLETON_PATTERN__
SingletonPattern.cpp
#include "SingletonPattern.h"
int main() {
Singleton *s1 = Singleton::getInstance();
// 不会创建第二个实例
Singleton *s2 = Singleton::getInstance();
system("pause");
return 0;
}
多线程环境测试单例模式
非线程安全 单例模式
#include "SingletonPattern.h"
#include <process.h>
#include <Windows.h>
#define THREAD_NUM 5
unsigned int __stdcall CallSingleton(void *pPM)
{
Singleton *s = Singleton::getInstance();
int nThreadNum = *(int *)pPM;
Sleep(50);
printf("线程编号为%d\n", nThreadNum);
return 0;
}
int main()
{
HANDLE handle[THREAD_NUM];
//线程编号
int threadNum = 0;
while (threadNum < THREAD_NUM)
{
handle[threadNum] = (HANDLE)_beginthreadex(NULL, 0, CallSingleton, &threadNum, 0, NULL);
//等子线程接收到参数时主线程可能改变了这个i的值
threadNum++;
}
//保证子线程已全部运行结束
WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);
system("pause");
return 0;
}
一共创建了5个线程,每个线程里面都试图创建一个单例对象。理论上,最终只有第一个线程(第一个被系统调度的线程)才会打印出“创建新的实例”,然而运行结果如下:
表明该单例模式的代码不是线程安全的。
线程安全的单例模式代码实现
SingletonPattern.h
/* 线程不安全 */
/*
#ifndef __SINGLETON_PATTERN__
#define __SINGLETON_PATTERN__
#include <iostream>
#include <string.h>
using namespace std;
// 抽象产品类AbstractBall
class Singleton {
public:
static Singleton *getInstance() {
if (instance == NULL) {
cout << "创建新实例" << endl;
instance = new Singleton();
}
return instance;
}
private:
Singleton() {}
static Singleton *instance;
};
Singleton *Singleton::instance = NULL;
#endif __SINGLETON_PATTERN__
*/
/* 线程安全的方法,采用互斥锁 */
#ifndef __SINGLETON_PATTERN__
#define __SINGLETON_PATTERN__
#include <iostream>
#include <string.h>
#include <mutex> // 信号量
using namespace std;
class Singleton {
public:
static Singleton *getInstance() {
if (instance == NULL) {
// 互斥锁
m_mutex.lock();
if (instance == NULL) {
cout << "创建新的实例" << endl;
instance = new Singleton();
}
m_mutex.unlock();
}
return instance;
}
private:
Singleton() {}
static Singleton *instance;
static std::mutex m_mutex;
};
Singleton *Singleton::instance = NULL;
std::mutex Singleton::m_mutex;
#endif __SINGLETON_PATTERN__
运行结果如下:

本文介绍了设计模式中的原型模式和单例模式的概念、实现方式及其优缺点。原型模式通过复制现有的实例来创建新的对象,简化了创建过程;单例模式确保一个类只有一个实例,并提供全局访问点。
538

被折叠的 条评论
为什么被折叠?



