模式概述
Prototype模式即原型模式,提供一个已经存在的对象进行新对象创建的接口,一般情况下都是使用Clone接口。
此模式非常简单,简单的说就是复制多个当前对象供使用。Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。
原型模式中的拷贝分为“浅拷贝”和“深拷贝”:
浅拷贝:对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象。
深拷贝:对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制。
这个模式一看就知道怎么回事了,网上有些博客和一些书上都用《西游记》中孙悟空的示例。确实,当我们的孙哥想要小弟时,猴毛一拔,成千上万的小弟就出来了。当然还有很多实际我们开发中的情况。例如:游戏开发时,有时经常要创建分身,二个、三个、或者十几个分身。由于分身需要拥有当前本体的一些数据。因此,此时使用用Prototype模式再合适不过了。
模式结构
Prototype模式结构如下:
Prototype模式非常简单,很有意思的是,Prototype模式与单键模式是相背的过程,Prototype模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对Prototype模式无效。还记得Singleton模式吗?Singleton模式中,只要将构造方法的访问权限设置为private型,就可以实现Singleton。但是clone方法直接无视构造方法的权限,所以,Singleton模式与Prototype模式是冲突的,在使用时要特别注意。
模式讨论
Prototype模式为何要用,这里可能要就说明下Prototype模式工作本质了。在C++中Prototype模式是使用拷贝构造函数(按位拷贝)实现的,直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。因此Prototype模式应该具有如下优点:
1. 复制大对象时,性能提升相当明显
2. 复制对象时,接口简单,就象复制粘贴一样。
3. 可以创建带有数据的对象,而非空对象
然而Prototype模式也并非我们想象中的那么美好,在Prototype模式中,由于在C++中Prototype模式是使用拷贝构造函数(按位拷贝)实现的,直接操作内存中的二进制流。所以经常我们要面临深拷贝与浅拷贝。(主要是指在有指针和复合对象存在的情况)
C++万恶之源,我深信深拷贝与浅拷贝肯定是占有一席之地的。那么何为深拷贝何为浅拷贝呢?
浅拷贝:
我们都知道当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:
(1)一个对象以值传递的方式传入函数体
(2)一个对象以值传递的方式从函数返回
(3)一个对象需要通过另外一个对象进行初始化。
如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝。
深拷贝:
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝。
综上,我认为在以下几种情况中比较合适采用原型模式来创建对象:
1、对象的构造函数非常复杂,在生成新对象的时候非常耗时间、耗资源的情况,使用原型模式可以避免构复杂造函数调用。使用拷贝构造函数节省资源(这里要特别注意拷贝构造函数的实现)
2、程序运行过程中,由于一些数据随进都在变化,事后很难使用构造函数再构造出一个和原来一样的对象。
3、不知道当前对象的状态,即目前不知道当前对象成员变量的值都变成了什么内容,故无法再用构造函数来构造和当前对象一样的对象了。
4、需要创建副本进行对比,在开发中,经常复杂的对象经常会变动。http://如果需http://要对比变动的部分,此时可以创建一个此时对象的副本。时间片后的对象与保存的副本进行对比,就相当容易发现哪些地方进行了变动。
创建模式到此结束,我们一起来回顾下创建模式吧!
Singleton模式:
确保一个类只有唯一的一个实例
http://blog.csdn.net/xiaoting451292510/article/details/8285710
Simple Factory模式:
定义创建对象的接口,并封装对象的创建
http://blog.csdn.net/xiaoting451292510/article/details/8289608
Complex Factory模式
1 定义创建对象的接口,并封装对象的创建
2 将具体化类的工作延迟到了类中
http://blog.csdn.net/xiaoting451292510/article/details/8290809
Abstract Factory模式
1 定义创建对象的接口,并封装对象的创建
2 将具体化类的工作延迟到了类中
3 创建创建一组相关对象或者说是一组相互依赖的对象
http://blog.csdn.net/xiaoting451292510/article/details/8290814
Buider模式
1. 需要创建的对象是复杂对象
2. 对象的创建过程是一步步创建(即:可能由于过程的不同而导致有不同的对象展示)
http://blog.csdn.net/xiaoting451292510/article/details/8330462
Prototype模式:
提供一个已经存在的对象进行新对象创建的接口,一般情况下都是使用Clone接口。
http://blog.csdn.net/xiaoting451292510/article/details/8478818
最后,无论模式多么优越,我们也需要根据实际的具体情况而慎重考虑。
模式实现
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
以后的笔记潇汀会尽量详细讲解一些相关知识的,希望大家继续关注我的博客。
本节笔记到这里就结束了。
潇汀一有时间就会把自己的学习心得,觉得比较好的知识点写出来和大家一起分享。
编程开发的路很长很长,非常希望能和大家一起交流,共同学习,共同进步。
如果文章中有什么疏漏的地方,也请大家指正。也希望大家可以多留言来和我探讨编程相关的问题。
最后,谢谢你们一直的支持~~~
C++完整个代码示例(代码在VS2005下测试可运行)
代码及相关下载地址:
http://download.csdn.net/detail/xiaoting451292510/5038152
DesignPattern.cpp
// DesignPattern.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#ifndef CXX_DESIGNPATTERN_SINGLETON_H
#include "DESIGNPATTERN_Singleton.h"
#endif
#ifndef CXX_PROFESSION_H
#include "Profession.h"
#endif
#ifndef CXX_DESIGNPATTERN_SIMPLEFACTORY_H
#include "DESIGNPATTERN_SimpleFactory.h"
#endif
#ifndef CXX_DESIGNPATTERN_COMPLEXFACTORY_H
#include "DESIGNPATTERN_ComplexFactory.h"
#endif
#ifndef CXX_MOUSE_H
#include "Mouse.h"
#endif
#ifndef CXX_KEYBOARD_H
#include "Keyboard.h"
#endif
#ifndef CXX_MONITOR_H
#include "Monitor.h"
#endif
#ifndef CXX_HOST_H
#include "Host.h"
#endif
#ifndef CXX_DESIGNPATTERN_ABSTRACTFACTORY_H
#include "DESIGNPATTERN_AbstractFactory.h"
#endif
#ifndef CXX_DESIGNPATTERN_DIRECTOR_H
#include "CXX_DESIGNPATTERN_Director.h"
#endif
#ifndef CXX_DESIGNPATTERN_BUILDER_H
#include "DESIGNPATTERN_Builder.h"
#endif
#ifndef CXX_COMPUTER_H
#include "Computer.h"
#endif
#ifndef CXX_DESIGNPATTERN_PROTOTYPE_H
#include "DESIGNPATTERN_Prototype.h"
#endif
#ifndef CXX_DESIGNPATTERN_CONCRETEPROTOTYPE_H
#include "DESIGNPATTERN_ConcretePrototype.h"
#endif
int _tmain(int argc, _TCHAR* argv[])
{
#if DEBG_TEST_SINGLETON
cout<<"***************************Singleton***************************"<<endl;
Singleton* pSingletonA = NULL;
Singleton* pSingletonB = NULL;
pSingletonA = Singleton::Instance();
pSingletonB = Singleton::Instance();
Singleton::Destroy();
Singleton::Destroy();
#endif
#if DEBG_TEST_SIMPLEFACTORY
cout<<"***************************SimpleFactory***************************"<<endl;
Singleton* pSingletonA = NULL;
Profession* pProfession[3] = {0};
for (int i=0; i<3; i++) {
pProfession[i] = SimpleFactory::Instance()->CreateProfession(i);
}
for (int i=0; i<3; i++) {
if (NULL != pProfession[i]) {
delete pProfession[i];
pProfession[i] = NULL;
}
}
#endif
#if DEBG_TEST_COMPLEXFACTORY
cout<<"***************************ComplexFactory***************************"<<endl;
ComplexFactory* pWarriorFactory = WarriorFactory::Instance();
ComplexFactory* pMasterFactory = MasterFactory::Instance();
Profession* pWarrior = pWarriorFactory->CreateProfession();
Profession* pMaster = pMasterFactory->CreateProfession();
if (NULL != pWarrior) {
delete pWarrior;
pWarrior = NULL;
}
if (NULL != pMaster) {
delete pMaster;
pMaster = NULL;
}
#endif
#if DEBG_TEST_ABSTRACTFACTORY
cout<<"***************************AbstractFactory***************************"<<endl;
AbstractFactory* pDELLFactory = DELLFactory::Instance();
AbstractFactory* pASUSFactory = ASUSFactory::Instance();
AbstractFactory* pHPFactory = HPFactory::Instance();
//DELL product
Mouse* pDellMouse = pDELLFactory->CreateMouse();
Keyboard* pDellKeyboard = pDELLFactory->CreateKeyboard();
Monitor* pDellMonitor = pDELLFactory->CreateMonitor();
Host* pDellHost = pDELLFactory->CreateHost();
//ASUS product
Mouse* pASUSMouse = pASUSFactory->CreateMouse();
Keyboard* pASUSKeyboard = pASUSFactory->CreateKeyboard();
Monitor* pASUSMonitor = pASUSFactory->CreateMonitor();
Host* pASUSHost = pASUSFactory->CreateHost();
//HP product
Mouse* pHPMouse = pHPFactory->CreateMouse();
Keyboard* pHPKeyboard = pHPFactory->CreateKeyboard();
Monitor* pHPMonitor = pHPFactory->CreateMonitor();
Host* pHPHost = pHPFactory->CreateHost();
if (NULL != pDellMouse) {
delete pDellMouse;
pDellMouse = NULL;
}
if (NULL != pDellKeyboard) {
delete pDellKeyboard;
pDellKeyboard = NULL;
}
if (NULL != pDellMonitor) {
delete pDellMonitor;
pDellMonitor = NULL;
}
if (NULL != pDellHost) {
delete pDellHost;
pDellHost = NULL;
}
if (NULL != pHPMouse) {
delete pHPMouse;
pHPMouse = NULL;
}
if (NULL != pHPKeyboard) {
delete pHPKeyboard;
pHPKeyboard = NULL;
}
if (NULL != pHPMonitor) {
delete pHPMonitor;
pHPMonitor = NULL;
}
if (NULL != pHPHost) {
delete pHPHost;
pHPHost = NULL;
}
if (NULL != pASUSMouse) {
delete pASUSMouse;
pASUSMouse = NULL;
}
if (NULL != pASUSKeyboard) {
delete pASUSKeyboard;
pASUSKeyboard = NULL;
}
if (NULL != pASUSMonitor) {
delete pASUSMonitor;
pASUSMonitor = NULL;
}
if (NULL != pASUSHost) {
delete pASUSHost;
pASUSHost = NULL;
}
#endif
#if DEBG_TEST_BUILDER
cout<<"***************************Builder***************************"<<endl;
Director* pDellDirector = new Director(DELLBuilder::Instance());
AbstractComputer* pDellComputer = pDellDirector->CreateComputer();
Director* pASUSDirector = new Director(ASUSBuilder::Instance());
AbstractComputer* pASUSComputer = pASUSDirector->CreateComputer();
Director* pHPDirector = new Director(HPBuilder::Instance());
AbstractComputer* pHPComputer = pHPDirector->CreateComputer();
if (NULL != pDellComputer) {
delete pDellComputer;
pDellComputer = NULL;
}
if (NULL != pASUSComputer) {
delete pASUSComputer;
pASUSComputer = NULL;
}
if (NULL != pHPComputer) {
delete pHPComputer;
pHPComputer = NULL;
}
#endif
#if DEBG_TEST_PROTOTYPE
cout<<"***************************DEBG_TEST_PROTOTYPE***************************"<<endl;
Prototype* pPrototype = new ConcretePrototype;
Prototype* pPrototypeTemp = pPrototype->Clone();
if (NULL != pPrototype) {
delete pPrototype;
pPrototype = NULL;
}
if (NULL != pPrototypeTemp) {
delete pPrototypeTemp;
pPrototypeTemp = NULL;
}
#endif
return 0;
}
DESIGNPATTERN_Prototype.h
/**
@file DESIGNPATTERN_Prototype.h
@brief 1. Copy a large object, the performance increase is quite obvious
2. Copy objects, simple interface, like copy and paste.
3. You can create a data object, rather than an empty object
@author arvin
@version 1.0 2013/01/29
*/
#ifndef CXX_DESIGNPATTERN_PROTOTYPE_H
#define CXX_DESIGNPATTERN_PROTOTYPE_H
class Prototype
{
public:
/**
* Destruction
*
* @param VOID
* @return
*/
virtual ~Prototype();
/**
* Create Computer
*
* @param VOID
* @return Prototype*
* @note
*/
virtual Prototype* Clone() const = 0;
protected:
/**
* Construction
*
* @param VOID
* @return
*/
Prototype();
private:
/**
* Copy Construction
*
* @param const Prototype& cPrototype
* @return
*/
Prototype(const Prototype& cPrototype);
/**
* Assignment
*
* @param const Prototype& cPrototype
* @return Prototype&
*/
Prototype& operator=(const Prototype& cPrototype);
public:
protected:
private:
};
#endif /* >>CXX_DESIGNPATTERN_PROTOTYPE_H<< */
/* EOF */
DESIGNPATTERN_ConcretePrototype.h
/**
@file DESIGNPATTERN_ConcretePrototype.h
@brief 1. Copy a large object, the performance increase is quite obvious
2. Copy objects, simple interface, like copy and paste.
3. You can create a data object, rather than an empty object
@author arvin
@version 1.0 2013/01/29
*/
#ifndef CXX_DESIGNPATTERN_CONCRETEPROTOTYPE_H
#define CXX_DESIGNPATTERN_CONCRETEPROTOTYPE_H
#ifndef CXX_DESIGNPATTERN_PROTOTYPE_H
#include "DESIGNPATTERN_Prototype.h"
#endif
class ConcretePrototype : public Prototype
{
public:
/**
* Construction
*
* @param VOID
* @return
*/
ConcretePrototype();
/**
* Destruction
*
* @param VOID
* @return
*/
virtual ~ConcretePrototype();
/**
* Create Computer
*
* @param VOID
* @return Prototype*
* @note
*/
virtual Prototype* Clone() const;
protected:
private:
/**
* Copy Construction
*
* @param const ConcretePrototype& cPrototype
* @return
*/
ConcretePrototype(const ConcretePrototype& cPrototype);
/**
* Assignment
*
* @param const ConcretePrototype& cPrototype
* @return ConcretePrototype&
*/
ConcretePrototype& operator=(const ConcretePrototype& cPrototype);
public:
protected:
private:
};
#endif /* >>CXX_DESIGNPATTERN_CONCRETEPROTOTYPE_H<< */
/* EOF */
DESIGNPATTERN_Prototype.cpp
/**
@file DESIGNPATTERN_Prototype.cpp
@brief 1. Copy a large object, the performance increase is quite obvious
2. Copy objects, simple interface, like copy and paste.
3. You can create a data object, rather than an empty object
@author arvin
@version 1.0 2013/01/29
*/
#include "stdafx.h"
#ifndef CXX_DESIGNPATTERN_PROTOTYPE_H
#include "DESIGNPATTERN_Prototype.h"
#endif
/**
* Construction
*
* @param VOID
* @return
*/
Prototype::Prototype()
{
}
/**
* Destruction
*
* @param VOID
* @return
*/
Prototype::~Prototype()
{
}
/**
* Create Computer
*
* @param VOID
* @return Prototype*
* @note
*/
Prototype*
Prototype::Clone() const
{
//system error log
cerr<<"[AbstractFactory::CreateMouse] got called from thread "<</*ThreadID*/"at: "/**gettimeofday()*/<<endl;
return NULL;
}
/* EOF */
DESIGNPATTERN_ConcretePrototype.cpp
/**
@file DESIGNPATTERN_ConcretePrototype.cpp
@brief 1. Copy a large object, the performance increase is quite obvious
2. Copy objects, simple interface, like copy and paste.
3. You can create a data object, rather than an empty object
@author arvin
@version 1.0 2013/01/29
*/
#include "stdafx.h"
#ifndef CXX_DESIGNPATTERN_CONCRETEPROTOTYPE_H
#include "DESIGNPATTERN_ConcretePrototype.h"
#endif
/**
* Construction
*
* @param VOID
* @return
*/
ConcretePrototype::ConcretePrototype()
{
}
/**
* Destruction
*
* @param VOID
* @return
*/
ConcretePrototype::~ConcretePrototype()
{
}
/**
* Create Computer
*
* @param VOID
* @return Prototype*
* @note
*/
Prototype*
ConcretePrototype::Clone() const
{
return new ConcretePrototype(*this);
}
/**
* Copy Construction
*
* @param const ConcretePrototype& cPrototype
* @return
*/
ConcretePrototype::ConcretePrototype(const ConcretePrototype& cPrototype)
{
}
/* EOF */