《Head First 设计模式》笔记23-原型模式

  1. 定义
  2. 模式结构
  3. 模式实现
  4. 优缺点

定义

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝。

深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值。

模式结构

原型模式主要包含如下三个角色:

  • Prototype:抽象原型类。声明克隆自身的接口。
  • ConcretePrototype:具体原型类。实现克隆的具体操作。
  • Client:客户类。让一个原型克隆自身,从而获得一个新的对象。

所有的 Java 类都继承至 Object,而 Object 类提供了一个 clone() 方法,该方法可以将一个 java 对象复制一份,因此在 java 中可以直接使用 clone() 方法来复制一个对象。但是需要实现 clone 的 Java 类必须要实现一个接口: Cloneable. 该接口表示该类能够复制且具体复制的能力,如果不实现该接口而直接调用 clone() 方法会抛出 CloneNotSupportedException 异常。如下:

public class PrototypeDemo implements Cloneable{
  public Object clone(){
    Object object = null;
    try {
      object = super.clone();
    } catch (CloneNotSupportedException exception) {
      System.err.println("Not support cloneable");
    }
    return object;
    }
    //……
}

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

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

模式实现

简历:Resume.java

public class Resume implements Cloneable {
    private String name;
    private File file;

    /**
     * 构造函数:初始化简历
     */
    public Resume(String name, File file){
        this.name = name;
        this.file = file;
    }

    /**
     * 克隆该实例
     */
    public Object clone() {
        Resume resume = null;
        try {
            resume = (Resume) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return resume;
    }

    public void display(){
        System.out.println("简历名:" + name + ",简历文件:" + file);
    }

}

客户端: Client.java

public class Client {
    public static void main(String[] args) {
        //原型A对象
        Resume a = new Resume("小李子", "1.pdf");

        //克隆B对象
        Resume b = (Resume) a.clone();

        //输出A和B对象
        System.out.println("----------------A--------------");
        a.display();
        System.out.println("----------------B--------------");
        b.display();
    }
}

打印结果:A,B相同,因为 clone() 是浅复制。

修改 clone() 方法

public Object clone() {
    Resume resume = null;
    try {
        resume = (Resume) super.clone();
        resume.field = this.field.clone();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    return resume;
}

这样如果字段很多,会比较麻烦。所以可以使用序列化。

/* 深复制 */
public Object deepClone() throws IOException, ClassNotFoundException {

    /* 写入当前对象的二进制流 */
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(this);

    /* 读出二进制流产生的新对象 */
    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(bis);
    return ois.readObject();
}

优缺点

优点

  1. 如果创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率。
  2. 可以使用深克隆保持对象的状态。
  3. 原型模式提供了简化的创建结构。

缺点

  1. 在实现深克隆的时候可能需要比较复杂的代码。
  2. 需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了 “开闭原则”。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com

文章标题:《Head First 设计模式》笔记23-原型模式

文章字数:945

本文作者:Bin

发布时间:2018-08-05, 16:35:17

最后更新:2019-08-06, 00:07:35

原始链接:http://coolview.github.io/2018/08/05/Head-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E3%80%8AHead-First-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%8B%E7%AC%94%E8%AE%B023-%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录