设计模式--原型模式

Posted chongcheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式--原型模式相关的知识,希望对你有一定的参考价值。

 如果文章中哪里有问题,希望各位大哥大姐指出,小弟十分感激。

正文

什么是原型模式?

  原型模式就是在原有对象的基础上,复制一个新的,但是内容一摸一样的对象。

为什么要使用原型模式?

  我们在日常业务中可能会有很多大对象(内部有很多字段),或者创建过程非常繁琐并耗时的对象。对于这些对象,如果我们需要一个新的对象时,重新创建往往是非常繁琐并且耗时的。而使用原型模式,就可以快速创建出一个完全一样的新对象。

怎样使用原型模式?

  1:被克隆的类及其引用属性类都要继承Cloneable空接口。
  2:被克隆的类及其引用属性类都要实现clone()方法。
  3:需要创建新对象时直接调用被克隆的类的clone()方法。

使用原型模式的时候一定要注意浅拷贝和深拷贝:

  浅拷贝:Object类的clone()方法会在内存在开辟一块新内容,并将原来对象的信息复制过来。因为基本数据类型内存里面存的就是他的值,所以直接复制过来没有问题;但是引用数据类型保存在内存中的是引用的目标对象的内存地址,所以复制后,新对象和旧对象的引用属性都是同一个内存空间,会相互影响,并不是完全的克隆。这就是浅拷贝。

  深拷贝:对于类内部的引用类型的属性,我们也让其实现Cloneable接口,并重写clone方法,然后在外层克隆对象的clone方法中手动执行一下引用类型属性的clone方法,再进行赋值一下,相当于对引用类型的属性进行一次手动赋值。注意,引用类型属性中的引用类型属性,也要这样操作,也就是套娃。

 

技术图片

 

 技术图片

/**
 *     原型模式
 * */
public class clone {
    public static void main(String[] args) {
        /** 创建大对象 */
        BigObject bigObject = new BigObject();
        bigObject.field1 = 111;
        bigObject.field2 = 111.11;
        bigObject.field3 = "最外层大对象";
        bigObject.field4 = false;
        bigObject.innerClass1 = new InnerClass1(222,222.22,"第二层innerClass1",true,new InnerClass3(333,333.33,"第三层innerClass1",true));
        bigObject.innerClass2 = new InnerClass2(444,444.44,"第二层innerClass2",false);
        /** 克隆大对象 */
        BigObject newObject = bigObject.clone();
        /** 输出比较一下 */
        
        System.err.println(bigObject.getClass().getName() + "@" + Integer.toHexString(bigObject.hashCode()));
        System.err.println(bigObject);
        System.err.println("");
        System.err.println(newObject.getClass().getName() + "@" + Integer.toHexString(newObject.hashCode()));
        System.err.println(newObject);
    }
}

/**
 *     大对象,需要实现Cloneable这个空接口,这是原型模式的关键
 * */
class BigObject implements Cloneable{
    int field1;
    Double field2;
    String field3;
    boolean field4;
    InnerClass1 innerClass1;
    InnerClass2 innerClass2;
    
    public BigObject(int field1, Double field2, String field3, boolean field4, InnerClass1 innerClass1,
            InnerClass2 innerClass2) {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
        this.field4 = field4;
        this.innerClass1 = innerClass1;
        this.innerClass2 = innerClass2;
        imitateDelay();
    }
    public BigObject() {
        imitateDelay();
    }
    /**
     *     模拟延迟
     * */
    @SuppressWarnings("static-access")
    private void imitateDelay() {
        try {
            // 模拟创建这个对象需要花费2秒
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     *     重写克隆方法,这是原型模式的关键
     * */
    @Override
    public BigObject clone() {
        BigObject newObject = null;
        try {
            /** 
             *     这里一定要调用父类的构造方法,决不能调用自己子类的构造方法,不然会死循环的
             *     super.clone()这个方法会在内存中开辟一个新空间,并将当前对象堆中的内容复制过去
             *     如果是基本数据类型,则是直接把值复制过去。
             *     但如果是引用类型,仅仅只是将引用对象的地址复制过去了而已。这会造成浅拷贝。
             *     旧对象和新对象的引用类型属性是同一块内存空间。
             *     对于String、Double这种不可变的,我们可以不管他,就算引用同一个内存空间,反正它里面的值是固定不会变的
             * */
            newObject = (BigObject)super.clone();
            newObject.innerClass1 = innerClass1.clone();
            newObject.innerClass2 = innerClass2.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return newObject;
    }
    @Override
    public String toString() {
        return "BigObject [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4
                + ", innerClass1=" + innerClass1 + ", innerClass2=" + innerClass2 + "]";
    }
    
}

class InnerClass1 implements Cloneable{
    int field1;
    Double field2;
    String field3;
    boolean field4;
    InnerClass3 innerClass;
    @Override
    public String toString() {
        return "InnerClass1 [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4
                + ", innerClass=" + innerClass + "]";
    }
    public InnerClass1(int field1, Double field2, String field3, boolean field4, InnerClass3 innerClass) {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
        this.field4 = field4;
        this.innerClass = innerClass;
    }
    /**
     *     重写克隆方法,这是深拷贝的关键
     * */
    @Override
    public InnerClass1 clone() {
        InnerClass1 newObject = null;
        try {
            /** 
             *     这里一定要调用父类的构造方法,决不能调用自己子类的构造方法,不然会死循环的
             *     super.clone()这个方法会在内存中开辟一个新空间,并将当前对象堆中的内容复制过去
             *     如果是基本数据类型,则是直接把值复制过去。
             *     但如果是引用类型,仅仅只是将引用对象的地址复制过去了而已。这会造成浅拷贝。
             *     旧对象和新对象的引用类型属性是同一块内存空间。
             *     对于String、Double这种不可变的,我们可以不管他,就算引用同一个内存空间,反正它里面的值是固定不会变的
             * */
            newObject = (InnerClass1)super.clone();
            newObject.innerClass = innerClass.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return newObject;
    }
}
class InnerClass2 implements Cloneable{
    int field1;
    Double field2;
    String field3;
    boolean field4;
    @Override
    public String toString() {
        return "InnerClass2 [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4
                + "]";
    }
    public InnerClass2(int field1, Double field2, String field3, boolean field4) {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
        this.field4 = field4;
    }
    /**
     *     重写克隆方法,这是深拷贝的关键
     * */
    @Override
    public InnerClass2 clone() {
        InnerClass2 newObject = null;
        try {
            /** 
             *     这里一定要调用父类的构造方法,决不能调用自己子类的构造方法,不然会死循环的
             *     super.clone()这个方法会在内存中开辟一个新空间,并将当前对象堆中的内容复制过去
             *     如果是基本数据类型,则是直接把值复制过去。
             *     但如果是引用类型,仅仅只是将引用对象的地址复制过去了而已。这会造成浅拷贝。
             *     旧对象和新对象的引用类型属性是同一块内存空间。
             *     对于String、Double这种不可变的,我们可以不管他,就算引用同一个内存空间,反正它里面的值是固定不会变的
             * */
            newObject = (InnerClass2)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return newObject;
    }
}
class InnerClass3 implements Cloneable{
    int field1;
    Double field2;
    String field3;
    boolean field4;
    @Override
    public String toString() {
        return "InnerClass3 [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4
                + "]";
    }
    public InnerClass3(int field1, Double field2, String field3, boolean field4) {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
        this.field4 = field4;
    }
    /**
     *     重写克隆方法,这是深拷贝的关键
     * */
    @Override
    public InnerClass3 clone() {
        InnerClass3 newObject = null;
        try {
            /** 
             *     这里一定要调用父类的构造方法,决不能调用自己子类的构造方法,不然会死循环的
             *     super.clone()这个方法会在内存中开辟一个新空间,并将当前对象堆中的内容复制过去
             *     如果是基本数据类型,则是直接把值复制过去。
             *     但如果是引用类型,仅仅只是将引用对象的地址复制过去了而已。这会造成浅拷贝。
             *     旧对象和新对象的引用类型属性是同一块内存空间。
             *     对于String、Double这种不可变的,我们可以不管他,就算引用同一个内存空间,反正它里面的值是固定不会变的
             * */
            newObject = (InnerClass3)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return newObject;
    }

}

 

以上是关于设计模式--原型模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之原型模式(Prototype)详解及代码示例

设计模式课程 设计模式精讲 9-2 原型模式coding

设计模式--原型模式

设计模式原型模式

Java设计模式----原型模式

设计模式--------原型模式