设计模式之原型模式

来源:互联网 发布:手机淘宝怎么改差评 编辑:程序博客网 时间:2024/05/21 10:44

原型模式用于复制对象,需要实现Cloneable接口,重写Object类中的clone()。

对于一个对象x来说,复制一般是要达到以下效果,虽然不是强制的:
1. x.clone != x 为true
2. x.clone.getClass() == x.getClass() 为true
3. x.clone.equals(x) 为true

通常重写clone()是重写成调用super.clone(),如果一个类及其所有父类都有符合这个标准,则x.clone.getClass() == x.getClass()是成立的。

如果要实现equals()为true,则要重写equals()自行实现逻辑比较。

如果一个类只包含基本数据类型或者对于不可变对象的引用,则只需直接返回super.clone()的对象即可。

但是如果这个类包含了可变对象,如果只是单纯复制一层,则只会复制可变对象的引用,实际指向的还是同一个可变对象。所以需要对可变对象进行复制,然后获取到复制后对象的引用,才能实现深层复制。

既然调用了super.clone(),则需要把Object类的clone()所进行的操作弄清楚。Object.clone()首先会检查这个类是否实现了Cloneable接口,如果没有就会抛出CloneNotSupportedException。

所有的数组默认都实现了Cloneable接口,对于一个任意类型数组T[],它的clone方法返回就是T[]。

检查实现了Cloneable接口之后,这个方法会创建这个类的新实例,然后以所复制对象的对应字段值来初始化新实例,就好像是正常赋值一样。注意这里并没有把字段本身也复制了,即如果是对象的话只复制引用,所以Object.clone()默认只是浅复制。

Object类本身并没有实现Cloneable接口,本身clone()也是protected。如果子类没有实现Cloneable接口,就重写clone()权限并调用,会抛出异常。

浅复制

目标类:

public class Student implements Cloneable {    private String name;    private int age;    public Student(String name, int age) {        this.name = name;        this.age = age;    }    @Override    public Student clone() {        try {            return (Student) super.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        return null;    }    @Override    public boolean equals(Object obj) {        if (obj == null) {            return false;        }        if (!(obj instanceof Student)) {            return false;        }        Student counterPart = (Student) obj;        return name.equals(counterPart.name) && age == counterPart.age;    }    @Override    public String toString() {        return "name = " + name + ", age = " + age;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}

测试类:

public class Test {    public static void main(String[] args) {        Student tim = new Student("Tim", 26);        Student timClone = tim.clone();        System.out.println(tim == timClone);        System.out.println(tim.getClass() == timClone.getClass());        System.out.println(tim.equals(timClone));        tim.setAge(10);        System.out.println(tim);        System.out.println(timClone);    }}

输出:

falsetruetruename = Tim, age = 10name = Tim, age = 26

深复制

如果所复制对象包含可变对象引用,则浅复制只能复制其引用,如果所引用的对象发生改变,则复制得到对象的对应可变对象也会发生改变,指向的是同一片内存,这种情况下就需要深复制。

深复制的实现是通过可变对象也实现Cloneable接口,重写clone()。然后得到外层复制对象后,对其可变对象进行再次复制。

下面给Student添加一个Subject对象字段以说明过程:
目标类:

public class Student implements Cloneable {    private String name;    private int age;    private Subject subject;    public Student(String name, int age, Subject subject) {        this.name = name;        this.age = age;        this.subject = subject;    }    @Override    public Student clone() {        try {            Student student = (Student) super.clone();            student.setSubject(subject.clone());            return student;        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        return null;    }    @Override    public boolean equals(Object obj) {        if (obj == null) {            return false;        }        if (!(obj instanceof Student)) {            return false;        }        Student counterPart = (Student) obj;        return name.equals(counterPart.name) && age == counterPart.age && subject.equals(counterPart.subject);    }    @Override    public String toString() {        return "name = " + name + ", age = " + age + ", subject = " + subject;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public Subject getSubject() {        return subject;    }    public void setSubject(Subject subject) {        this.subject = subject;    }}

目标类所包含的可变字段类:

public class Subject implements Cloneable {    String name;    public Subject(String name) {        this.name = name;    }    @Override    public Subject clone() {        try {            return (Subject) super.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        return null;    }    @Override    public boolean equals(Object obj) {        if(obj == null){            return false;        }        if(!(obj instanceof Subject)){            return false;        }        Subject counterPart = (Subject)obj;        return this.name.equals(counterPart.name);    }    @Override    public String toString() {        return name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

测试类:

public class Test {    public static void main(String[] args) {        Subject subject = new Subject("Math");        Student tim = new Student("Tim", 26, subject);        Student timClone = tim.clone();        System.out.println(tim == timClone);        System.out.println(tim.getClass() == timClone.getClass());        System.out.println(tim.equals(timClone));        tim.setAge(10);        subject.setName("English");        System.out.println(tim);        System.out.println(timClone);    }}

输出:

falsetruetruename = Tim, age = 10, subject = Englishname = Tim, age = 26, subject = Math
原创粉丝点击