设计模式-创建型模式-原型模式

概念

复制代码
原型模式 : Prototype Pattern : 是一种创建型设计模式。
作用 : 通过复制现有的对象来创建新对象,无需通过new 来实例化新对象,从而达到简化对象创建的效果。

原型 : prototype : 定义用于复制自身以生成新对象的方法。通常 称为 clone()

【Object 类中,提供了一个 clone() 方法,该方法可以将一个Java对象复制一份,但是需要实现 Cloneable 接口】
具体原型 :ConcretePrototype : 实现了 原型接口的具体的类,对 clone() 进行了具体的实现。
客户端 : Client : 使用具体原型对象来克隆新对象的应用程序代码。

拷贝的方式

浅拷贝

复制代码
【定义】 : 
1、浅拷贝是指创建一个新对象,然后将当前对象的非静态字段复制到该新对象。
2、如果字段是基本数据类型,则直接复制其值;但如果字段是引用类型,则复制的是引用地址,而不是引用的对象本身。
3、这意味着原始对象和副本对象中的引用类型字段将指向内存中的同一个对象。

【特点】 :
1、基本数据类型的字段被直接复制。
2、引用类型的字段只复制了引用,并没有复制引用的对象。
3、原始对象与副本对象共享引用类型的成员变量所指向的对象,任何一方对这些共享对象的修改都会影响另一方。

深拷贝

复制代码
【定义】: 
1、深拷贝不仅会创建一个新的对象,还会递归地复制所有引用类型字段指向的对象。
2、这意味着原始对象和副本对象的所有字段,包括基本数据类型和引用类型,都是完全独立的。

【特点】:
1、基本数据类型的字段同样被直接复制。
2、引用类型的字段也会被复制,不仅仅是引用地址,还包括引用的对象本身也被复制了一份。
3、原始对象与副本对象之间没有共享的对象,因此对任何一个对象的修改都不会影响另一个对象。

案例

主要是看 clone() 方法。

浅拷贝

原型类

java 复制代码
// 实现 Cloneable 接口
public class Student implements Cloneable {

    private String name;
    private int age;

    构造方法
    getter
    setter
    toString

    // 核心 : clone 方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 简单的 浅拷贝
        return super.clone();
    }
}

测试代码

java 复制代码
public class PrototyoeTest {
    public static void main(String[] args) throws CloneNotSupportedException {

        Student s1 = new Student("张三", 18);
        Student s2 = (Student) s1.clone();
        Student s3 = (Student) s1.clone();
        System.out.println("s1 : "+s1 + " - "+s1.hashCode());
        System.out.println("s2 : "+s2 + " - "+s2.hashCode());
        System.out.println("s3 : "+s3 + " - "+s3.hashCode());
    }
}
复制代码
运行结果 : 
s1 : Student{name='张三', age=18} - 931919113
s2 : Student{name='张三', age=18} - 1531448569
s3 : Student{name='张三', age=18} - 1867083167

深拷贝

方式一:直接手动写一下

java 复制代码
public class School implements Cloneable {
    private String name;
    private String address;

	构造方法
    getter
    setter
    toString

 	@Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
java 复制代码
public class Student implements Cloneable {

    private String name;
    private int age;

    private School school; // 一个引用对象,深拷贝也会被拷贝

    构造方法
    getter
    setter
    toString


    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 深拷贝-手动进行引用对象的
        Student cloneObj = (Student) super.clone();
        // 手动的将引用的对象获取出来,重新赋值
        School cloneSchool = (School) this.getSchool().clone();
        cloneObj.setSchool(cloneSchool);

        return cloneObj;
    }
}

方式二:流式操作 - 推荐使用

涉及到 流式操作,需要进行序列化及反序列化,因此也会用到 Serializable 接口。

java 复制代码
public class School implements Serializable {
    private String name;
    private String address;

    构造方法
    getter
    setter
    toString
}
java 复制代码
public class Student implements Cloneable, Serializable {

    private String name;
    private int age;

    private School school;
   构造方法
    getter
    setter
    toString


    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 深拷贝-使用流的方式进行对象的拷贝
        /**
         * 流程:
         * 1、将对象转换成字节数组,写入 字节输出流中
         * 2、从字节输入流中读取字节,再转换成对象,返回
         */

        ByteArrayInputStream bis = null;
        ByteArrayOutputStream bos = null;
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;

        try{

            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); // 将对象写入到字节输出流中

            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            return ois.readObject(); // 从字节输入流中读取对象

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                if (bis != null){
                    bis.close();
                }
                if (bos != null){
                    bos.close();
                }
                if (ois != null){
                    ois.close();
                }
                if (oos != null){
                    oos.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        return null;

    }
}

测试类

java 复制代码
public class PrototyoeTest {
    public static void main(String[] args) throws CloneNotSupportedException {

        Student s1 = new Student("张三", 18);
        s1.setSchool(new School("清华大学", "北京"));

        Student s2 = (Student) s1.clone();
        Student s3 = (Student) s1.clone();

        System.out.println("s1 : "+s1 + " - "+s1.hashCode() + " - "+s1.getSchool().hashCode());
        System.out.println("s2 : "+s2 + " - "+s2.hashCode() + " - "+s2.getSchool().hashCode());
        System.out.println("s3 : "+s3 + " - "+s3.hashCode() + " - "+s3.getSchool().hashCode());
    }
}
复制代码
s1 : Student{name='张三', age=18, school=School{name='清华大学', address='北京'}} - 1607521710 - 764977973
s2 : Student{name='张三', age=18, school=School{name='清华大学', address='北京'}} - 500977346 - 20132171
s3 : Student{name='张三', age=18, school=School{name='清华大学', address='北京'}} - 186370029 - 2094548358
相关推荐
charlie1145141917 小时前
精读C++20设计模式:行为型设计模式:中介者模式
c++·学习·设计模式·c++20·中介者模式
虫师c10 小时前
分布式系统设计模式:从理论到实践
微服务·设计模式·系统架构·高可用·分布式系统
半旧夜夏10 小时前
【设计模式】核心设计模式实战
java·spring boot·设计模式
ThisIsMirror12 小时前
设计模式简要介绍
设计模式
魔云连洲15 小时前
深入解析:Object.prototype.toString.call() 的工作原理与实战应用
前端·javascript·原型模式
Lei活在当下17 小时前
【业务场景架构实战】7. 多代智能手表适配:Android APP 表盘编辑页的功能驱动设计
android·设计模式·架构
澄澈i19 小时前
设计模式学习[20]---桥接模式
c++·学习·设计模式·桥接模式
o0向阳而生0o21 小时前
106、23种设计模式之备忘录模式(15/23)
设计模式·备忘录模式
小猪佩奇TONY1 天前
C++ 学习(3) ----设计模式
c++·学习·设计模式
zhulangfly2 天前
轻松理解智能体设计模式(1/6):提示链(Prompt Chaining)
设计模式·prompt chaining