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

概念

原型模式 : 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
相关推荐
玖石书20 小时前
【高内聚】设计模式是如何让软件更好做到高内聚的?
设计模式
晚秋贰拾伍21 小时前
设计模式的艺术-观察者模式
运维·观察者模式·设计模式·运维开发
小王子10241 天前
设计模式Python版 建造者模式
python·设计模式·建造者模式
Cikiss1 天前
「全网最细 + 实战源码案例」设计模式——适配器模式
java·后端·设计模式·适配器模式
NorthCastle2 天前
设计模式-创建型模式-抽象工厂模式
设计模式·抽象工厂模式
咖啡の猫2 天前
解释器模式
设计模式·解释器模式
Cikiss2 天前
「全网最细 + 实战源码案例」设计模式——原型模式
java·后端·设计模式·原型模式
小王子10242 天前
设计模式Python版 原型模式
python·设计模式·原型模式
HHhha.3 天前
Java进阶(二):Java设计模式
java·开发语言·设计模式