美文网首页技术专栏23天学习23种设计模式程序员
23天学习23种设计模式——原型模式

23天学习23种设计模式——原型模式

作者: soberbad | 来源:发表于2017-10-08 15:55 被阅读62次

前言

类似于《西游记》中的孙悟空拔出猴毛,根据自己的样子变出很多猴子来。或者是《火影忍者》中鸣人使用影分身变出很多个鸣人来。设计模式中的原型模式,也是根据原型(如同孙悟空,鸣人本人就是原型)创建出新的对象。

是什么

原型模式(prototype pattern)是一种创建型模式,使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

原型模式UML类图

为什么

原型模式多用于创建复杂的或构造耗时的实例,这样就能高效地创建实例对象,减轻创建对象的成本。

怎么做

在Java中,所有的类都继承自java.lang.Object类,而该类提供了clone()方法,这个本地方法可以将Java对象复制一份。但是需要注意的是,必须要实现标识接口Cloneable来标识这个类可以被复制。

clone()方法

下面通过一个例子来实现原型模式,这是一个实现了Cloneable接口的类,并重载了Object类的clone方法。

/**
 * 实现Cloneable接口表示该类可以被复制
 */
public class Sheep implements Cloneable{

    private String name;
    private Date birthDate;

    public Sheep(String name,Date date) {
        this.name = name;
        this.birthDate = date;
    }

    public Date getBirthDate() {
        return birthDate;
    }

    public String getName() {
        return name;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    public void setName(String name) {
        this.name = name;
    }

    /**
     * 重载Object类的clone方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //  浅复制
        return super.clone();
    }

    @Override
    public String toString() {
        return "Sheep<"+hashCode()+">'s name="+name+" birthdate:"
                +birthDate.toString()+" name hashcode:"+name.hashCode()+" birthdate hashcode:"+birthDate.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        Sheep another = (Sheep) obj;
        return this.name.equals(another.name)&&this.birthDate.compareTo(another.birthDate)==0;
    }
}

现在我们来测试一下上面那个类对象的复制,

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {

        Date birthDate = new Date(1341314415234L);
        String name = "duoli";
        Sheep duoli = new Sheep(name,birthDate);

        Sheep cloneSheep = (Sheep) duoli.clone();

        System.out.println(duoli.toString());
        System.out.println(cloneSheep.toString());

        birthDate.setTime(2124124124L);

        System.out.println(duoli.toString());
        System.out.println(cloneSheep.toString());
    }
}
运行结果

从上面运行结果截图可以知道,原型对象和克隆对象的值是一样的,但是修改原型对象的属性之后,克隆对象的相应属性也被修改了。这是由于浅复制导致的。也就是说克隆对象只复制了原型对象的地址。当该地址对应的原型对象的值发生变化时,有着相同地址的克隆对象的属性也会发生变化。

浅复制

这个问题可以通过深复制来解决,在深复制中,除了对象本身被复制外,对象所有的属性也会被复制。

深复制

对于Sheep类,我们可以进行如下的修改:

  ...
   @Override
    protected Object clone() throws CloneNotSupportedException {
        //Deep Clone
        Sheep sheep = (Sheep) super.clone();
        sheep.birthDate = (Date) birthDate.clone();
        sheep.name = name;
        return sheep;
}
...

虽然,这种方式看起来比较简单,这是由于我们直接使用了引用类型Date类已经实现好了的clone方法。
对于我们自定义的类,往往我们要去实现Cloneable接口,并重写Object类的clone()方法。

我们还可以通过序列化的方式(Serialization)来实现。通过IO流操作把对象写入流中,流中的对象就是原有对象的拷贝,不仅复制了对象本身,而且可以复制其引用的成员属性。所以,将对象写入流中,然后从流中读出来,就能实现深复制了。

下面通过将clone方法中修改为序列化操作来实现深复制:

 @Override
    protected Object clone() throws CloneNotSupportedException {
        //Deep Clone
//        Sheep sheep = (Sheep) super.clone();
//        sheep.birthDate = (Date) birthDate.clone();
//        sheep.a = (A) a.clone();
//        sheep.name = name;
//        return sheep;

        try {
            return deepClone();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
}
 /**
     * 使用IO技术实现深复制
     * @return
     */
    public Sheep deepClone() throws IOException, ClassNotFoundException {

        //将对象写入IO流中
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(this);

        //将对象从IO流中取出来
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Sheep clone = (Sheep) ois.readObject();

        baos.close();
        oos.close();
        bais.close();
        ois.close();

        return clone;
    }
序列化深复制拷贝

相关文章

  • JavaJavascript基础进阶(十七)JS中常用的设计模式

    单利设计模式、构造原型设计模式、发布订阅设计模式、promise设计模式 单利模式 构造原型设计模式 最贴近OOP...

  • 学习笔记2020-05-13

    今天学习了: 1、原型模式 2、KNN 3、空气炸锅 4、苦瓜炒鸡蛋没做好 1、设计模式-原型模式 原型模式,就是...

  • Spring 准备内容

    准备内容 原型设计模式 PropotypeModle 原型模式也属于创造型设计模式,用原型实例指定创建对象的种类,...

  • 设计模式问答(一)

    设计模式问答(一) 什么是设计模式?您能说出工厂模式、抽象工厂模式、创建者模式、原型模式、原型模式的潜复制及深复制...

  • 28 Java设计模式系列-原型模式

    原型模式 原型模式是非常常见的设计模式之一,写个笔记,记录一下我的学习过程和心得。 首先了解一些原型模式的定义。 ...

  • 原型和原型链篇

    原型和原型链 1.理解原型设计模式以及JavaScript中的原型规则 原型设计模式JavaScript是一种基于...

  • 设计模式整理(4) 原型模式

    学习《Android 源码设计模式解析与实践》系列笔记 介绍 原型模式是一种创建型的模式。原型模式就是用户从一个样...

  • 初始设计模式之原型模式

    原型模式是什么? 原型模式怎么用?浅拷贝深拷贝 原型模式再理解 一、原型模式是什么? ​ 原型模式是一种创建型设计...

  • 常用开源框架中设计模式使用分析-原型设计模式(Prototype

    五、原型设计模式(Prototype Pattern) 5.1 介绍 相比单例设计模式,原型模式是每次创建一个对象...

  • 2021-11-16 - 学习记录

    设计模式学习:创建型:工厂(工厂方法,抽象工厂),建造者,单例,原型 设计模式:工厂模式 简单工厂 工厂方法 抽象工厂

网友评论

    本文标题:23天学习23种设计模式——原型模式

    本文链接:https://www.haomeiwen.com/subject/urtryxtx.html