一个菜鸡JAVA后端的博客~

设计模式-原型模式

定义

  • Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype(用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象)
  • 原型模式简单程度仅次于单例模式和迭代器模式,其核心是一个Clone方法,通过该方法进行对象的拷贝。

优点

  • 性能优良:原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好的体现其优点。

  • 逃避构造函数的约束:这是它的优点也是它的缺点,直接在内存中拷贝,

    构造函数是不会执行的。优点和缺点就是减少了约束

使用场景

  • 场景:
    • 资源优化场景:类初始化需要消耗非常多的资源,这个资源包括数据、硬件资源等。
    • 性能和安全要求的场景:通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
    • 一个对象多个修改者的场景:一个对象需要提供给其他对象访问,而且各个调用者都可能需要修改其值时,可以使用原型模式拷贝多个对象给调用者调用。
    • 利用原型模式先产生一个包含大量共有信息的类,然后可以拷贝出副本,修正细节信息,建立一个完整的个性对象。

代码

通用类图

原型模式通用类图

基本的建造者模式

类图

没有,就一个类

代码

原型设计模式代码

package com.pattern;

import com.pattern.prototype.PrototypeClass;
import org.junit.Test;

public class PrototypeTest {
    @Test
    public void PrototypeTest(){
        PrototypeClass instance1 = new PrototypeClass();
        try {
            PrototypeClass instance2 = instance1.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

测试代码

package com.pattern;

import com.pattern.prototype.PrototypeClass;
import org.junit.Test;

public class PrototypeTest {
    @Test
    public void PrototypeTest(){
        PrototypeClass instance1 = new PrototypeClass();
        try {
            PrototypeClass instance2 = instance1.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

结果

原型模式执行结果

浅拷贝和深拷贝

代码

浅拷贝

package com.pattern.prototype;

import java.util.ArrayList;

public class ShallowCopy implements Cloneable {
    private ArrayList<String> arrayList = new ArrayList<>();
    @Override
    public ShallowCopy clone(){
        ShallowCopy shallowCopy = null;
        try {
            shallowCopy = (ShallowCopy) super.clone();
        } catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return shallowCopy;
    }
    public void addValue(String value){
        this.arrayList.add(value);
    }
    public ArrayList<String> getArrayList(){
        return this.arrayList;
    }
}

测试代码

    @Test
    public void ShallowCopyTest(){
        ShallowCopy instance1 = new ShallowCopy();
        instance1.addValue("1");
        ShallowCopy instance2 = instance1.clone();
        instance2.addValue("2");
        System.out.println(instance1.getArrayList());
    }

运行结果

浅拷贝运行结果

深拷贝

package com.pattern.prototype;

import java.util.ArrayList;

public class DeepCopy implements Cloneable {
    private ArrayList<String> arrayList = new ArrayList<>();
    @Override
    public DeepCopy clone(){
        DeepCopy deepCopy = null;
        try {
            deepCopy = (DeepCopy) super.clone();
            deepCopy.arrayList = (ArrayList<String>) this.arrayList.clone();
        } catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return deepCopy;
    }
    public void addValue(String value){
        this.arrayList.add(value);
    }
    public ArrayList<String> getArrayList(){
        return this.arrayList;
    }
}

测试代码

    @Test
    public void DeepCopyTest(){
        DeepCopy instance1= new DeepCopy();
        instance1.addValue("1");
        DeepCopy instance2 = instance1.clone();
        instance2.addValue("2");
        System.out.println(instance1.getArrayList());
    }

运行结果

深拷贝运行结果

我们发现,在浅拷贝的时候,改变instance2中arraylist的值导致instance1的值也改变了,而在深拷贝则没这样的情况。这是因为Java做了一个偷懒的动作。

Object类提供的方法Clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这就是浅拷贝。两个对象共享了一个私有变量。这是一种非常不安全的,至于String类为什么也会被拷贝。请自行网上查阅资料。

注意

  • 原型模式的构造函数不会被执行,Object类的clone方法是从内存中(堆内存)以二进制流的方式进行拷贝,重新分配一个内存块。
  • 浅拷贝和深拷贝
  • 原型模式,引用的成员变量必须满足两个条件才会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象
  • 深拷贝和浅拷贝不建议混合使用,特别是涉及到类的继承时,父类有多个引用的情况就非常复杂,建议方案是浅拷贝和深拷贝分开实现

NOTE: 文章若无特别说明均为原创文章,如果要转载请保留出处!