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

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中,原型模式可以很简单地实现,只要实现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()并不会对其进行拷贝,需自行提供深拷贝;

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值