原文参考书籍:《Design Patterns Explained Simply》
一、定义
根据保存的原型寻找需创建对象的类型,再通过拷贝(clone)依据类型创建新的对象。
二、结构
三、要点
- 原型模式中,Client并不知道要克隆对象的实际类型,只需知道基类类型即可。
- 克隆对象比直接创建对象的优点在于,克隆是将原有对象的行为属性带到了新的对象中。
- C++没有克隆方法,要克隆一个对象,需要借助拷贝构造函数(Copy Constructor)来实现。拷贝构造函数中实现拷贝对象有浅拷贝和深拷贝。
四、代码
1. prototype.h
#ifndef PROTOTYPE_H #define PROTOTYPE_H #include <iostream> using namespace std; enum imageType { LSAT,SPOT }; class Image { public: virtual void draw()=0; static Image *findAndClone(imageType); protected: virtual imageType returnType()=0; virtual Image *clone()=0; // As each subclass of Image is declared,it registers its prototype static void addPrototype(Image *image) { _prototypes[_nextSlot++] = image; } private: // addPrototype() saves each registered prototype here static Image *_prototypes[10]; static int _nextSlot; }; Image *Image::_prototypes[]; int Image::_nextSlot; // Client calls this public static member function when it needs an instance of an Image subclass Image *Image::findAndClone(imageType type) { for(int i=0;i<_nextSlot;i++) if(_prototypes[i]->returnType()==type) return _prototypes[i]->clone(); } class LandSatImage:public Image { public: imageType returnType(){ return LSAT; } void draw(){ cout <<"LandSatImage::draw"<<_id<<endl; } // When clone()is called,call the one-argument ctor with a dummy arg Image *clone(){ return new LandSatImage(1); } protected: //This is only called from clone() LandSatImage(int dummy){ _id=_count++; } private: //Mechanism for initializing an Image subclass-this causes the // default ctor to be called,which registers the subclass's prototype static LandSatImage _landSatImage; //This is only called yhen the private static data member is inited LandSatImage() { addPrototype(this); } // Nominal "state" per instance mechanism int _id; static int _count; }; // Register the subclass's prototype LandSatImage LandSatImage::_landSatImage; // Initialize the"state" per instance mechanism int LandSatImage::_count = 1; class SpotImage:public Image { public: imageType returnType(){ return SPOT; } void draw(){ cout <<"SpotImage:draw"<<_id<<endl; } Image *clone(){ return new SpotImage(1); } protected: SpotImage(int dummy){ _id=_count++; } private: SpotImage(){ addPrototype(this); } static SpotImage _spotImage; int _id; static int _count; }; SpotImage SpotImage::_spotImage; int SpotImage::_count = 1; #endif
2. prototype.cpp
#include "prototype.h" // Simulated stream of creation requests const int NUM_IMAGES=8; imageType input[NUM_IMAGES]= { LSAT,LSAT,LSAT,SPOT,LSAT,SPOT,SPOT,LSAT }; int main() { Image *images[NUM_IMAGES]; // Given an image type,find the right prototype,and return a clone for(int i=0;i<NUM_IMAGES;i++) images[i]=Image::findAndClone(input[i]); //Demonstrate that correct image objects have been cloned for(int i=0;i<NUM_IMAGES;i++) images[i]->draw(); // Free the dynamic memory for(int i=0;i<NUM_IMAGES;i++) delete images[i]; return 0; }