您的位置:首页 > 其它

设计模式(4)-对象创建型模式-Prototype模式

2016-01-14 14:48 274 查看

1.对象创建型模式

1.4 Protoype模式

1.4.1需求

通过拷贝原形对象创建新的对象。

1.4.2结构



•P r o t o t y p e(Gr a p h i c)

— 声明一个克隆自身的接口。

•C o n c r e t e P r o t o t y p e(S t a ff、W h o l e N o t e、H a l fN o t e)

— 实现一个克隆自身的操作。

• C l i e n t(G r a p h i c To o l)

— 让一个原型克隆自身从而创建一个新的对象。

1.4.3样例-C++

//Prototype.h

#ifndef _PROTOTYPE_H_

#define _PROTOTYPE_H_

class Prototype

{

public:

virtual ~Prototype();

virtual Prototype*Clone()const = 0;

protected:

Prototype();

private:

};

class ConcretePrototype:public Prototype

{

public:

ConcretePrototype();

ConcretePrototype(const ConcretePrototype& cp);

~ConcretePrototype();

Prototype* Clone() const;

protected:

private:

};

#endif //~_PROTOTYPE_H_

代码片断2:Prototype.cpp

//Prototype.cpp

#include"Prototype.h"

#include<iostream>

using namespace std;

Prototype::Prototype()

{

}

Prototype::~Prototype()

{

}

Prototype* Prototype::Clone() const

{

return 0;

}

ConcretePrototype::ConcretePrototype()

{

}

ConcretePrototype::~ConcretePrototype()

{

}

ConcretePrototype::ConcretePrototype(const ConcretePrototype& cp)

{

cout<<"ConcretePrototype copy..."<<endl;

}

Prototype* ConcretePrototype::Clone() const

{

return newConcretePrototype(*this);

}

//main.cpp

#include"Prototype.h"

#include<iostream>

using namespace std;

int main(int argc,char*argv[])

{

Prototype* p= newConcretePrototype();

Prototype* p1=p->Clone();

return 0;

}

注:这里仅仅是说明概念,没有涉及C++常见的深度拷贝问题.

1.4.4 样例-JAVA

在Java中,原型模式能够非常easy地实现,仅仅要实现Cloneable这个标识性的接口,再覆盖该接口中的clone()方法,就可以“克隆”该实现类的不论什么一个对象。

class ConcretePrototype02 implements Cloneable{

private String name;

private ArrayList<String> nameList = new ArrayList<String>();

public ConcretePrototype02(String name) {

this.name = name;

this.nameList.add(this.name);

}

//加入nameList中的对象

public void setName(String name) {

this.nameList.add(name);

}

public ArrayList<String> getNameList() {

return this.nameList;

}

//覆盖Object基类中的clone()方法,并扩大该方法的訪问权限,详细化返回本类型

public ConcretePrototype02 clone() {

ConcretePrototype02self = null;

try {

self= (ConcretePrototype02) super.clone();

//下面这句是实现深拷贝的关键

// self.nameList =(ArrayList<String>) this.nameList.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return self;

}

}

//測试类

public class Client {

public static void main(String[] args) {

ConcretePrototype02prototype02 = new ConcretePrototype02("蚂蚁 ...");

System.out.println(prototype02.getNameList());

//通过clone获得一个拷贝

ConcretePrototype02fromClone02 = prototype02.clone();

fromClone02.setName("小蚂蚁 ...");

System.out.println(fromClone02.getNameList());

System.out.println(prototype02.getNameList());

}

}

測试结果:

拷贝之前的原型: [蚂蚁 ...]

拷贝得到的对象: [蚂蚁 ..., 小蚂蚁 ...]

拷贝之后的原型: [蚂蚁 ..., 小蚂蚁 ...]

发现拷贝之后原来的对象持有的ArrayList<String>类型的nameList引用会随着拷贝得到的fromClone对象运行了setName()方法而改变。这不是我们想要的结果,由于这意味着原型以及拷贝得到的对象共享同一个引用变量,这是线程不安全的。当我们去掉
上面clone()方法中被凝视的语句之后再測试,得到结果例如以下:

拷贝之前的原型: [蚂蚁 ...]

拷贝得到的对象: [蚂蚁 ..., 小蚂蚁 ...]

拷贝之后的原型: [蚂蚁 ...]

在Java中使用原型模式Prototype是相当简单的,仅仅要记住几点注意点,就能够方便地实现该模式了。

因为使用clone()方法来拷贝一个对象是从内存二进制流中进行IO读写。所以拷贝得到一个对象是不会运行该对象所相应类的构造函数的。

总结例如以下:

1、构造函数不会被运行。

2、类的成员变量中若有引用类型的变量(数组也是一种对象)。默认的clone()并不会对其进行拷贝,需自行提供深拷贝;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: