博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式学习笔记(6)——原型模式
阅读量:6897 次
发布时间:2019-06-27

本文共 3625 字,大约阅读时间需要 12 分钟。

  hot3.png

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

类型:创建类模式

类图:

原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:

  • 实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。

  • 重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。

        原型模式是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式。在实际应用中,原型模式很少单独出现。经常与其他模式混用,他的原型类Prototype也常用抽象类来替代。

class Prototype implements Cloneable { public Prototype clone(){  Prototype prototype = null;  try{   prototype = (Prototype)super.clone();  }catch(CloneNotSupportedException e){   e.printStackTrace();  }  return prototype;  }}class ConcretePrototype extends Prototype{ public void show(){  System.out.println("原型模式实现类"); }}public class Client { public static void main(String[] args){  ConcretePrototype cp = new ConcretePrototype();  for(int i=0; i< 10; i++){   ConcretePrototype clonecp = (ConcretePrototype)cp.clone();   clonecp.show();  } }}

 Java中任何实现了Cloneable接口的类都可以通过调用clone()方法来复制一份自身然后传给调用者。一般而言,clone()方法满足:      

      (1) 对任何的对象x,都有x.clone() !=x,即克隆对象与原对象不是同一个对象。      
      (2) 对任何的对象x,都有x.clone().getClass()==x.getClass(),即克隆对象与原对象的类型一样。      
      (3) 如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

注意:以上方式实现的拷贝为浅拷贝~

如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝,例如:

方式一:

public class Prototype implements Cloneable { private ArrayList list = new ArrayList(); public Prototype clone(){  Prototype prototype = null;  try{   prototype = (Prototype)super.clone();   prototype.list = (ArrayList) this.list.clone();  }catch(CloneNotSupportedException e){   e.printStackTrace();  }  return prototype;  }}

由于ArrayList不是基本类型,所以成员变量list,不会被拷贝,需要我们自己实现深拷贝,幸运的是java提供的大部分的容器类都实现了Cloneable接口。所以实现深拷贝并不是特别困难。

方式二:

利用序列化实现深拷贝

把对象写到流里的过程是序列化(Serialization)过程;而把对象从流中读出来的过程则叫反序列化(Deserialization)过程。应当指出的是,写到流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。

在Java语言里深度克隆一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的拷贝)写到一个流里(序列化),再从流里读回来(反序列化),便可以重建对象。

public class DeepClone implements Serializable{    private int a;    private String b;    private int[] c;    public int getA()    {        return a;    }    public void setA(int a)    {        this.a = a;    }    public String getB()    {        return b;    }    public void setB(String b)    {        this.b = b;    }    public int[] getC()    {        return c;    }    public void setC(int[] c)    {        this.c = c;    }}
public Object deepClone(Object src)    {        Object o = null;        try        {            if (src != null)            {                // 将对象写到流里                ByteArrayOutputStream baos =new ByteArrayOutputStream();                ObjectOutputStream oos = newObjectOutputStream(baos);                oos.writeObject(src);                oos.close();                // 将对象从流里读出来                ByteArrayInputStream bais = newByteArrayInputStream(baos                        .toByteArray());                ObjectInputStream ois = newObjectInputStream(bais);                o = ois.readObject();                ois.close();            }        } catch (IOException e)        {            e.printStackTrace();        } catch (ClassNotFoundException e)        {            e.printStackTrace();        }        return o;    }

原型模式的优点及适用场景

       使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。

       使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。

       因为以上优点,所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。

原型模式向客户隐藏了创建对象的复杂性。客户只需要知道要创建对象的类型,然后通过请求就可以获得和该对象一模一样的新对象,无须知道具体的创建过程。注意深浅拷贝的区别~

转载于:https://my.oschina.net/jewill/blog/414414

你可能感兴趣的文章
macOS Sierra pip install psycopg2 error
查看>>
shell scripts 知识点汇总
查看>>
Kafka知识点汇总
查看>>
db2ckpwd, db2wdog为什么需要root用户运行.
查看>>
运维-常用命令
查看>>
centos6.6安装最新firefox和firefox-flash-plugin
查看>>
phpmyadmin 显式ip
查看>>
C语言类型
查看>>
有关Patent Agreement
查看>>
c 语言多参数
查看>>
php缓存加速插件安装记录
查看>>
python:threading多线程模块-Condition实现复杂的同步
查看>>
Centos7使用YUM进行install或update出现KeyboardInterrupt错误
查看>>
网络扫描工作zenmap
查看>>
Nginx技巧:灵活的server_name
查看>>
嵌入式开发那点事之一
查看>>
css直接画方格
查看>>
Qt多个信号连接到一个槽,在槽中识别信号的发送者方法
查看>>
IOS学习笔记2—Objective C—类、属性、方法
查看>>
How to hack windows 8 using kali linux
查看>>