设计模式-原型模式

75 阅读3分钟

一、原型模式介绍

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

原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。

使用前提:

  • 实现Cloneable接口。(运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。)
  • 重写Object类中的clone()方法。(返回对象的一个拷贝)

两种拷贝方式:

  • 浅拷贝
  • 深拷贝

二、浅拷贝

2.1 示例关系:

2.2 代码实现:

/* *
 * 定义一个Dog类,实现Cloneable接口。
 * 有带参构造方法。
 * 重写toString()、clone()方法。
 */

class Dog implements Cloneable {
    String name;
    int age;
    Dog friend;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    protected Object clone() {
        Object shallowCopyObj = null;
        try {
            shallowCopyObj = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return shallowCopyObj;
    }
}

public class PrototypeShallowCopy {
    public static void main(String[] args) {
        Dog tom = new Dog("tom", 2);
        // 为成员的对象类型赋值。
        tom.friend = new Dog("jack", 3);

        // 使用原型模式对对象进行克隆。
        Dog tom1 = (Dog) tom.clone();
        Dog tom2 = (Dog) tom.clone();

        System.out.println(" dog_info: " + tom  + " friend_hashCode: " + tom.friend.hashCode());
        System.out.println(" dog_info: " + tom1 + " friend_hashCode: " + tom1.friend.hashCode());
        System.out.println(" dog_info: " + tom2 + " friend_hashCode: " + tom2.friend.hashCode());
        // dog_info: Dog{name='tom', age=2} friend_hashCode: 968514068
        // dog_info: Dog{name='tom', age=2} friend_hashCode: 968514068
        // dog_info: Dog{name='tom', age=2} friend_hashCode: 968514068
        // 引用对象类型地址值一样。
    }
}

2.3 方式说明:

默认情况下原型模式使用的是浅拷贝

若成员变量是基本数据类型则直接进行值传递;若是某个类对象、某个数组等则将成员变量的内存地址复制给一个新的对象,实际上指向的都是同一实例

该拷贝方式下,修改一个对象的成员变量会影响另一个对象的成员变量值。

三、深拷贝

3.1 示例关系:

3.2 代码实现:

/* *
 * 定义一个Cat类,实现Cloneable、Serializable接口。
 * 有带参构造方法。
 * 重写toString()、clone()方法。
 */

class Cat implements Cloneable, Serializable {
    String name;
    int age;
    Cat friend;

    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    /* *
     * 通过序列化-反序列化方式实现。
     */

    @Override
    protected Object clone() {
        // 创建字节输入输出流、对象输入输出流。
        ByteArrayOutputStream bos = null;
        ByteArrayInputStream bis = null;
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;

        Cat deepCopyObj = null;
        try {
            // 序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            //当前对象以流形式输出
            oos.writeObject(this);

            // 反序列化。
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            deepCopyObj = (Cat) ois.readObject();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 资源释放。
            try {
                assert ois != null;
                ois.close();
                bis.close();
                oos.close();
                bos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return deepCopyObj;
    }
}

public class PrototypeDeepCopy {

    public static void main(String[] args) {
        Cat tom = new Cat("tom", 2);
        tom.friend = new Cat("jack", 3);

        Cat tom1 = (Cat) tom.clone();
        Cat tom2 = (Cat) tom.clone();

        System.out.println(" cat_info: " + tom  + " friend_hashCode: " + tom.friend.hashCode());
        System.out.println(" cat_info: " + tom1 + " friend_hashCode: " + tom1.friend.hashCode());
        System.out.println(" cat_info: " + tom2 + " friend_hashCode: " + tom2.friend.hashCode());
        // cat_info: Cat{name='tom', age=2} friend_hashCode: 1166726978
        // cat_info: Cat{name='tom', age=2} friend_hashCode: 1824835605
        // cat_info: Cat{name='tom', age=2} friend_hashCode: 981661423
        
        // 引用对象类型都是独立的。
    }
}

3.3 方式说明:

复制对象的所有基本数据类型的成员变量值。

为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。(即:独立且完整的方式进行拷贝)

四、总结:

使用原型模式简化了对象的重复创建过程。

两种方式区别:

  • 深拷贝就是对象引用和对象一起给复制了一遍,实现了这个物理上的完全隔离。

  • 浅拷贝则是简单的复制了对象的引用,实质上还是指向同一个对象。

  • 浅拷贝会带来数据安全方面的隐患,深拷贝相比于浅拷贝速度较慢并且花销较大。

工作原理: 通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象.clone()

需要注意: 原型模式(动态创建对象)与单例模式(只允许单个实例存在)是冲突的。

五 、结束语

“-------怕什么真理无穷,进一寸有一寸的欢喜。”

微信公众号搜索:饺子泡牛奶