设计模式之原型模式

介绍

原型模式就是一个原型对象,可以大量的克隆或者复制出与自己相同对象的模式,简称自我复制。是一种创建型模式。

优点

当构建一个对象比较复杂,且又大量使用到这种对象时,可以通过原型模式快速创建。

示例

如何让一个对象自我复制?

让实体类去实现java.lang.Cloneable并重写clone()方法。

public class Student implements Cloneable {
   private String no;
    private String name;
    private String age;

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

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

    @Override
    protected Object clone() {
        Student student=null;
        try {
            student=(Student) super.clone();
        }catch (Exception e){
            e.printStackTrace();
        }
        return student;
    }
}

测试:

public class Main {
    public static void main(String[] args) {
 		Student student=new Student("2222","张三","18");
        Student student1=(Student) student.clone();
        System.out.println(student1.toString());
    }
}

结果:

浅拷贝

假如说我们现在又给Student新增了一个属性friend:

public class Student implements Cloneable {
    private String no;
    private String name;
    private String age;
    public Student friend;
    public Student(String no, String name, String age,Student friend) {
        this.no = no;
        this.name = name;
        this.age = age;
        this.friend=friend;
    }

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

    @Override
    protected Object clone() {
        Student student=null;
        try {
            student=(Student) super.clone();
        }catch (Exception e){
            e.printStackTrace();
        }
        return student;
    }
}

再测试:

public class Main {
    public static void main(String[] args) {
        Student student2=new Student("1111","李四","20",null);
        Student student=new Student("2222","张三","18",student2);
        Student student1=(Student) student.clone();
        System.out.println(student.toString()+student.friend.hashCode());
        System.out.println(student1.toString()+student1.friend.hashCode());
    }
}

结果:

从结果看出,两个“student”的“friend”指向了同一个对象。

如图所示:

这就是传说中的浅拷贝,即复制对象属性时,只复制值,当有一个引用型属性时也只会复制值,只不过此时值是被应用对象地址。所以复制出的对象属性也会指向同一个对象。

深拷贝

有浅拷贝自然有深拷贝,深拷贝复制的时候,会为引用属性开辟新的空间。

如图所示:

实现深拷贝的方式有两种:

1.重写clone()方法。

先来说说重写clone()方法。如果我们在重写的时候将引用对象也显示的调用clone()去拷贝一份,那么就会为它分配内存空间.

  protected Object clone() {
        Student student=null;
        try {
            student=(Student) super.clone();
            student.friend=(Student) friend.clone();
        }catch (Exception e){
            e.printStackTrace();
        }
        return student;
    }

虽然实现了深拷贝,但是存在一个问题:引用型成员变量也得去实现java.lang.Cloneable并重写clone()方法,当被引用的类型十分多的时候,想想那个代码量就让人头疼,所以不推荐这种方式。这种方式只适合简单的,引用较少的原型模式。

2.通过序列化。

序列化首先要实现Serializable接口。

class Student implements Serializable {
    private String no;
    private String name;
    private String age;
    public Student friend;
    public Student(String no, String name, String age,Student friend) {
        this.no = no;
        this.name = name;
        this.age = age;
        this.friend=friend;
    }

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


    public Student objClone(){
        Student student=null;
        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);
            student=(Student) ois.readObject();
        }catch (Exception e){
            e.printStackTrace();
        }
        return student;
    }
}
posted @ 2020-05-30 01:14  网络小渣渣  阅读(66)  评论(0)    收藏  举报