1、传统方式的优缺点

  1. 优点是比较好理解,简单易操作
  2. 在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象过多,效率不高。
  3. 总是需要重新初始化对象,而不是动态的获取对象运行时的状态。

代码展示:

public class Student {

    private String id;
    private String name;

    public Student() {
    }

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

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

测试类

public class Test {

    public static void main(String[] args) {
        Student s1 = new Student("1","旺财");

        Student s2 = new Student(s1.getId(),s1.getName());
        Student s3 = new Student(s1.getId(),s1.getName());
        Student s4 = new Student(s1.getId(),s1.getName());
        Student s5 = new Student(s1.getId(),s1.getName());

        System.out.println("s1:"+s1);
        System.out.println("s2:"+s2);
        System.out.println("s3:"+s3);
        System.out.println("s4:"+s4);
        System.out.println("s5:"+s5);
    }

}

 

2、原型模式介绍

  1. 原型模式是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
  2. 原型设计模式是一种创建型设计模式,运行一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。
  3. 工作原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,既 对象.clone();
package com.hblg.prototype.improve;

/**
 * @author i
 * @create 2019/10/15 17:18
 * @Description
 */
public class Student implements  Cloneable{

    private String id;
    private String name;
    //添加一个引用对象类型
    private Student student;
    public Student() {
    }

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

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", student=" + student +
                '}';
    }

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

测试类

 //使用clone 对于基本数据类型来说拷贝的是原来值的一份。但是对于引用数据类型来说 直接将对象地址作为引用使用,也就是说指向的是同一块内存地址
    public static void main(String[] args) throws Exception {
        Student student = new Student("1","小强");
        student.setStudent(new Student("2","旺财"));
        Student s2 = (Student) student.clone();
        Student s3 = (Student) student.clone();
        System.out.println(student+" "+student.getStudent().hashCode());
        System.out.println(s2+" "+s2.getStudent().hashCode());
        System.out.println(s3+" "+s3.getStudent().hashCode());
    }

 

3、Spring中原型模式的使用

4、理解浅拷贝和深拷贝

  1. 对于基本数据类型是成员变量,浅拷贝会直接进行值拷贝,也就是将该属性值复制一份给新的对象。
  2. 对于引用数据类型是成员变量,如果该成员是数组或者是某个对象的实例。浅拷贝会进行引用传递,也就是将该成员的变量的引用值(内存地址)赋值一份直接给新的对象。因为实际上两个对象的该成员变量都指向了同一块内存区域,这这种情况下,在一个对象中修改该成员变量会影响到另一个对象的对该成员变量内容的修改。
  3. 浅拷贝obj.clone();

5、深拷贝基本介绍

  1. 复制对象的所有基本数据类型成员变量值。
  2. 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型变量所引用的对象,直到该对象可达的所有对象,也就是说。对象进行深拷贝要对整个对象进行深拷贝(包含引用数据类型)
  3. 方式1、重写clone()
  4. 方式2、通过对象序列化实现深拷贝。

Phone类

package com.hblg.prototype.deepclone;

import java.io.Serializable;

/**
 * @author i
 * @create 2019/10/15 17:36
 * @Description
 */
public class Phone implements Serializable,Cloneable {

    private Integer telNumber;
    private String phoneType;

    public Phone(Integer telNumber, String phoneType) {
        this.telNumber = telNumber;
        this.phoneType = phoneType;
    }

    public String getPhoneType() {
        return phoneType;
    }

    public void setPhoneType(String phoneType) {
        this.phoneType = phoneType;
    }

    public Integer getTelNumber() {
        return telNumber;
    }

    public void setTelNumber(Integer telNumber) {
        this.telNumber = telNumber;
    }

    @Override
    public String toString() {
        return "Phone{" +
                "telNumber=" + telNumber +
                ", phoneType='" + phoneType + '\'' +
                '}';
    }

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

StudentDeepClone类

package com.hblg.prototype.deepclone;

import java.io.*;

/**
 * @author i
 * @create 2019/10/15 17:34
 * @Description 实现深拷贝
 */
public class StudentDeepClone implements Serializable,Cloneable {

    private int id;
    private String name;
    private Phone phone;

    public StudentDeepClone(int id, String name, Phone phone) {
        this.id = id;
        this.name = name;
        this.phone = phone;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Phone getPhone() {
        return phone;
    }

    public void setPhone(Phone phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "StudentDeepClone{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", phone=" + phone +
                '}';
    }

    //深拷贝 方式1 使用clone方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        StudentDeepClone student = null;

        try {
            //实现对基本数据类型的拷贝
            student = (StudentDeepClone) super.clone();
            //实现对引用数据类型的拷贝
            student.setPhone((Phone)phone.clone());
        }catch (Exception e){
            e.printStackTrace();
        }
        return student;
    }

    //深拷贝 2 使用序列化方式
    public Object deepClone(){
        //使用流对象
        ByteArrayOutputStream bos = null;//字节数组输出流
        ObjectOutputStream oos = null;//对象输出流
        ByteArrayInputStream bis = null;//字节数组输入流
        ObjectInputStream ois = null;//对象输入流

        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);//将当前对象以输出流的方式进行输出

            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            StudentDeepClone s = (StudentDeepClone) ois.readObject();
            return s;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }
}

 

package com.hblg.prototype.deepclone;

/**
 * @author i
 * @create 2019/10/15 17:41
 * @Description
 */
public class Client {

    public static void main(String[] args) throws CloneNotSupportedException {
        StudentDeepClone s1 = new StudentDeepClone(1,"小强",new Phone(111,"Phone-X"));
        StudentDeepClone s2 = (StudentDeepClone) s1.clone();
        //1.深度拷贝 使用clone()
        System.out.println(s1+" "+s1.getPhone().hashCode());
        System.out.println(s2+" "+s2.getPhone().hashCode());

        //2.使用序列化进行深拷贝
//        StudentDeepClone s2 = (StudentDeepClone) s1.deepClone();
//        System.out.println(s1+" "+s1.getPhone().hashCode());
//        System.out.println(s2+" "+s2.getPhone().hashCode());

    }

}

 6、总结

  1. 创建新的对象比较复杂时,可以使用原型模式简化对象的创建过程,同时也能提高效率。
  2. 不用重新初始化对象,而是动态地获取对象运行的状态。
  3. 如果原始对象发生变化,其他克隆对象也会发生相应的变化,无需修改代码。