设计模式(二)——原型、单例、适配器、桥接模式

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

05 原型模式

原型模式

概念

原型模式:
使用原型实例指定带创建对象的类型,并且通过复制这个原型实例创建型的对象

三大角色

  1. 抽象原型类(AbstractPrototype):声明克隆clone自身的接口;
  2. 具体圆形类(ConcretePrototype):实现clone接口;
  3. 客户端(Client):客户端中声明一个抽象原型类,根据客户需求clone具体原型类对象实例。

克隆方法

将对象包含的所有属性都创建一份拷贝,但会产生两种拷贝结果:

  1. 浅拷贝:如果原型对象的成员使值类型(int,double,char等),将复制一份给拷贝对象;如果原型对象的成员变量是指针/引用,则将指针/引用指向的地址拷贝一份给拷贝对象,即原型对象和拷贝对象中的成员变量指向同一地址
  2. 深拷贝:无论原型对象中的成员变量是值类型还是指针/引用类型,都将复制一份给拷贝对象。

优点:

  1. 当创建新的对象实例较为复杂时,原型模式可以简化创建过程,提高创建对象的频率;
  2. 可扩展:模式中提供了抽象原型类,具体原型类可适当扩展;
  3. 创建结构简单:创建工厂即为原型对象本身。

缺点:

  1. 深复制代码较为复杂;
  2. 每一个类都得配备一个clone方法,且该方法位于类内部,修改违背了开闭原则

适用环境:

  1. 当创建新的对象实例较为复杂时,原型模式可以简化创建过程;
  2. 结合优点第三条,需要避免适用分层的工厂来创建分层的对象,并且类的实例对象只有一个或很少几个的组合状态,通过复制原型对象得到新的实例,比通过适用构造函数创建一个新的实例会更加方便

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 单例模式

概念

单例模式:
确保一个类只有以一个实例,并提供一个全局访问点来访问这个唯一的实例。

三要点

  1. 这个类只能有一个实例
  2. 必须自己创建这个实例
  3. 它必须自己向整个系统提供这个实例

可以看出,单例模式中,构造函数是私有的(private),即单例模式对象只能在类内部实例化,只能自己创建实例(满足单例模式第2个要点);同时,实例对象是静态的(static),满足第1点只有一个实例;第3个要点即外界如何获取这个单例对象:通过静态方法static getInstance()获取。

优点:

  1. 单例模式提供了严格的对唯一实例的创建和访问
  2. 单例模式的实现可以节省系统资源

缺点:

  1. 如果某个实例负责多重职责但又必须实例唯一,那单例类的职责过多,这违背了单一职责原则
  2. 多线程下需要考虑线程安全机制
  3. 单例模式没有抽象层,不方便扩展

适用环境:

  1. 系统只需要一个实例对象
  2. 某个实例只允许有一个访问接口

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__

运行结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值