Prototype模式——设计模式学习

    Prototype

一 意图

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

二 动机


  在图形编辑器中增加音符编辑构造乐谱编辑器的例子中。

GraphicTool作为图形编辑器的框架,其中提供了可以添加的图形;

Graphic作为图形类的基类,新增加的音乐相关符号也都从Graphic派生。

要实现乐谱构造器,需要新增加图形,供GraphicTool添加使用。

  如果仅仅是增加新的Graphic派生类,并且再对每一个Graphic实现copy自己。我想了很久也不知道怎么去实现……

增加了新的Graphic派生类,但是GraphicTool仍然是不知道增加了新的图形,要么扩展GraphicTooL支持的图形种类,

要么增加GraphicTooL派生类扩展。不管什么样的做法,我觉得都需要知道我们新增加了Graphic。

  所以我觉得使用Prototype模式在这里来实现图形扩展,而不改变客户端GraphicTool等代码,来支持新的特性,似乎有些不妥当。

Prototype模式——原型模式本身就要求先有原型然后才有Clone。

  当然我觉得这里每一个Graphic类增加Clone是十分必要的。在图形编辑器中,GraphicTool所支持的可以添加的每一类图形,

都是可以批量添加的,如果每添加或者copy一个图形都需要new一次然后初始化,对于复杂的对象,使用new是非常麻烦的事。

只需要为每一类图形保留一个原型,然后Clone Copy就可以了。


三 适用性与结构

 

  1. 当一个系统应该独立于产品创建,构成和表示时,要使用Prototype模式;
  2. 当要实例化的类是在运行时刻指定时,例如:通过动态加载
  3. 为了避免创建一个与产品类层次平行的工厂类层次时
  4. 当一个类的实例只能有几个不同的状态组合中的一种时,建立相应数目的原型

并Clone他们,而不用去手工创建和初始化。


四 代码实现

 1 基本形式

 

View Code
/***********************************************
* Class Frame *
*********************************************
*/
class Frame
{
public:
virtual void draw() = 0;
virtual Frame* Clone() = 0;
};

/***********************************************
* Class Title *
*********************************************
*/
class Title : public Frame
{
public:
Title(){}
Title(Title& other)
{
cout<<"copy title"<<endl;
}
virtual void draw()
{
cout<<"title draw"<<endl;
}
virtual Frame* Clone()
{
return new Title(*this);
}
};

/***********************************************
* Class Menu *
*********************************************
*/
class Menu : public Frame
{
public:
Menu(){}
Menu(Menu& other)
{
cout<<"copy menu"<<endl;
}
virtual void draw()
{
cout<<"menu draw"<<endl;
}
virtual Frame* Clone()
{
return new Menu(*this);
}
};

/***********************************************
* Class Toolbar *
*********************************************
*/
class Toolbar : public Frame
{
public:
Toolbar(){}
Toolbar(Toolbar& other)
{
cout<<"copy Toolbar"<<endl;
}
virtual void draw()
{
cout<<"Toolbar draw"<<endl;
}
virtual Frame* Clone()
{
return new Toolbar(*this);
}
};

 

 

2 使用原型管理器

View Code
//来自:http://sourcemaking.com/design_patterns/prototype/cpp/3
#include <iostream.h>

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 when 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;

// 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 (i = 0; i < NUM_IMAGES; i++)
images[i]->draw();

// Free the dynamic memory
for (i = 0; i < NUM_IMAGES; i++)
delete images[i];
}

 

 

五 总结

  Prototype模式在工作的平台使用较少。

  Prototype模式例子的实现中,都是只针对浅拷贝,如果具有对象的循环应用或者动态内存成员,那情况可能变得更加的复杂一些。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值