原型模式

Posted pain-first

tags:

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

--什么是原型模式?
--使用原型模式的应用场景?
--有哪几种原型模式?优缺点?
--原型模式的选择

定义

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。

应用场景

  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 对象的创建过程比较麻烦,但复制比较简单的时候。

两种原型模式

1.浅克隆

创建一个新对象,新对象的属性和原来对象完全相同,对于引用类型属性,仍指向原有属性所指向的对象的内存地址。
注:(1)引用数据类型包括:类、接口类型、数组类型、枚举类型、注解类型,字符串型;
(2)基本数据类型,其包括包括数值型,字符型和布尔型。
为了更好的演示,先创建个引用类
Row.java

public class Row implements Cloneable {
    private int n;

    //省略getter,setter

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

浅克隆实现了Cloneable接口,并重写clone方法。
ShallowClone.java

public class ShallowClone implements Cloneable{

    private String name;
    private Date birthday;
    private Row row;
    public ShallowClone() {
    }

    public ShallowClone(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    //省略getter,setter

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Row row = new Row();
        ShallowClone person1 = new ShallowClone("lihui", new Date());
        person1.setRow(row);
        ShallowClone person2 = (ShallowClone) person1.clone();
        row.setN(1); 
        System.out.println(person1 == person2); // false
        System.out.println(person1.row == person2.row); // true

    }
}

技术图片
debug看各个属性的引用地址,仔细观察不难发现,克隆的对象除了person2对象的内存地址地址和person1的不一致,其余的引用类型属性都指向相同的地址。 也就是说,当执行row.setN(1)的时候,不但会修改person1的row的值,也会修改person2的row的值。

2.深克隆

创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
深克隆不但实现了Cloneable接口和重写clone方法,该类的引用类型属性也实现了Cloneable接口和重写clone方法,并且在该类的clone方法中调用clone方法进行了赋值。
DeepClone.java

public class DeepClone implements Cloneable{
    private String name;
    private Date birthday;
    private int num;
    private Row row;
    public DeepClone() {
    }

    public DeepClone(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    //省略getter,setter

    @Override
    protected Object clone() throws CloneNotSupportedException {
        DeepClone person = (DeepClone) super.clone();
        // 这里对对象内的引用类型属性进行克隆,使克隆更深入
        person.row = (Row) person.row.clone();
        return person;
    }


    public static void main(String[] args) throws CloneNotSupportedException {
        Row row = new Row();
        DeepClone person1 = new DeepClone("lihui", new Date(0L));
        person1.setRow(row);
        DeepClone person2 = (DeepClone) person1.clone();
        row.setN(1); 
        System.out.println(person1 == person2); // false
        System.out.println(person1.row == person2.row); // false
    }
}

技术图片
debug看各个属性的引用地址,发现person2和person1的对象和所有引用类型的属性的地址都不一样。所以引用对象修改值的时候,只会影响到原本的引用地址里面的值,而不会影响到克隆对象属性的值。
也就是说,当执行row.setN(1)的时候,只会修改person1的row的值,不会修改person2的row的值。

区别

深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。

参考:
什么叫引用? https://blog.csdn.net/qq_44231628/article/details/86064762
浅克隆和深克隆 https://www.cnblogs.com/1314xf/p/10139971.html ????????????????????????https://www.jianshu.com/p/8caf745d8ca6

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

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

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

设计模式--原型模式

5.原型模式

设计模式原型模式

csharp 设计模式 - 原型 - 结构代码