设计模式 05 原型模式

原型模式(Prototype Pattern)属于创建型模式

概述

原型模式实际上就是对象的拷贝。

原型模式使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。也就是说,原型对象作为模板,通过克隆操作,来产生更多的对象,就像细胞的复制一样。

原型模式的拷贝分为浅拷贝深拷贝

代码实现

浅拷贝

对于类中基本数据类型,会直接复制值给拷贝对象。

对于类中引用类型,只会复制对象的地址,而实际上指向的还是原来的那个对象。

// 基本类型浅拷贝
int a = 10;
int b = a;
// 输出:true
System.out.println(a == b);

// 引用类型浅拷贝,拷贝的仅仅是对上面对象的引用
Object o = new Object();
Object k = o;
// 输出:true
System.out.println(o == k);

在 Java 中,就可以实现 Cloneable 接口提供的拷贝机制,来实现原型模式:

1、定义实体类实现 Cloneable 接口

/**
 * 用户
 * <p>注意需要实现 Cloneable 接口
 */
public class Student implements Cloneable {

    String name;

    public Student(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    /**
     * 提升clone方法的访问权限
     * @return 对象
     * @throws CloneNotSupportedException 不支持克隆异常
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

2、来看看克隆的对象是不是原来的对象

Student student0 = new Student();
Student student1 = (Student) student0.clone();
System.out.println(student0);
System.out.println(student1);

可以看到,通过 clone() 方法克隆的对象并不是原来的对象,我们来看看如果对象内部有属性会不会一起进行克隆:

public class Student implements Cloneable{
    
    String name;

    public Student(String name){
        this.name = name;
    }
    
    public String getName() {
        return name;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
Student student1 = new Student("程序航");
Student student2 = (Student) student1.clone();
// 输出:true
System.out.println(student1.getName() == student2.getName());
// 输出:false
System.out.println(student1 == student2);

可以看到,虽然 Student 对象成功拷贝,但是其内层对象并没有进行拷贝,依然只是对象引用的复制。所以 Java 为我们提供的 clone 方法只会进行浅拷贝。那么如何才能实现深拷贝呢?

深拷贝

无论是基本类型还是引用类型,深拷贝会将引用类型的所有内容,全部拷贝为一个新的对象,包括对象内部的所有成员变量,也会进行拷贝。

1、对成员变量也进行拷贝

@Override
public Object clone() throws CloneNotSupportedException {   
    Student student = (Student) super.clone();
    // 这里我们改进一下,针对成员变量也进行拷贝
    student.name = new String(name);
    // 成员拷贝完成后,再返回
    return student;   
}

2、再执行上述的代码

Student student1 = new Student("程序航");
Student student2 = (Student) student1.clone();
// 输出:false
System.out.println(student1.getName() == student2.getName());
// 输出:false
System.out.println(student1 == student2);

可以看到, Student 对象和其中的属性 name 都进行了拷贝,是完全不一样的对象了。这样就是拷贝生成了一个全新的对象,也就是深拷贝了。

优缺点

优点

1、性能提高。

2、逃避构造函数的约束。

缺点

1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。

2、必须实现 Cloneable 接口。

使用场景

1、资源优化场景。

2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。

3、性能和安全要求的场景。

4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。

5、一个对象多个修改者的场景。

6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。

7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,可以随手拿来使用。

注意事项

与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写 clone 方法;深拷贝是通过实现 Serializable 读取二进制流。


参考

https://www.bilibili.com/video/BV1mc411h719?p=6&vd_source=299f4bc123b19e7d6f66fefd8f124a03

posted @ 2022-07-21 22:48  天航星  阅读(31)  评论(0编辑  收藏  举报