1、 原型模式概念

该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。java中复制通过clone()实现的。clone中涉及深、浅复制。深、浅复制的概念如下:

⑴浅复制(浅克隆)
   型对象的成员变量是值类型,将复制一份给克隆对象值,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。 Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址
方法:调用 java.lang.Object的clone()方法
  ⑵深复制(深克隆)

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
方法:
1、对象内部所有引用型对象都进行clone。
2、对象序列化
原型模式代码

public class Prototype implements Cloneable{

    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    protected Object clone()   {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }finally {
            return null;
        }
    }

    public static void main ( String[] args){
        Prototype pro = new Prototype();
        Prototype pro1 = (Prototype)pro.clone();
    }
}

2、浅克隆:

/**
 * Created by yd on 2019/3/27.
 * 浅克隆
 */
public class Student implements Cloneable {
    private String name;
    private Subject subject;

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

    public String getName() {
        return name;
    }

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

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }

    public String toString(){
        return "name:"+name+"; subject:{"+subject+"}";
    }

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

    public static void main(String[] args) throws CloneNotSupportedException{
        Subject subject = new Subject("100","100");
        Student student = new Student("YYY",subject);
        System.out.println(student);
        Student st = (Student)student.clone();
        st.setName("ZZZ");
        st.getSubject().setChinese("99");
        System.out.println(student);
        System.out.println(st);
    }
}
class Subject {
    private String english;
    private String chinese;

    public Subject(String chinese,String english){
        this.chinese = chinese;
        this.english = english;
    }

    public String toString(){
        return "english : "+english+"; chinese:"+chinese;
    }
    public String getEnglish() {
        return english;
    }

    public void setEnglish(String english) {
        this.english = english;
    }

    public String getChinese() {
        return chinese;
    }

    public void setChinese(String chinese) {
        this.chinese = chinese;
    }
}

运行结果:

name:YYY; subject:{english : 100; chinese:100}
name:YYY; subject:{english : 100; chinese:99}
name:ZZZ; subject:{english : 100; chinese:99}

JAVA设计模式之原型模式

浅克隆对于引用类型,只克隆了引用,因此两个对象的subject公共同一个内存地址,一个对象变化,会引起另一个对象响应的变化。

3、深克隆:

import java.io.*;

/**
 * Created by yd on 2019/3/28.
 * 深克隆
 */
public class Student2 implements Serializable,Cloneable{
    private String name;
    private Subject2 subject2;

    public Student2(String name,Subject2 subject2){
        this.name = name;
        this.subject2 = subject2;
    }

    public String getName() {
        return name;
    }

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

    public Subject2 getSubject2() {
        return subject2;
    }

    public void setSubject2(Subject2 subject2) {
        this.subject2 = subject2;
    }

    @Override
    public String toString(){
        return "name:"+name+"; subject:{"+subject2+"}";
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student2 student2 = (Student2)super.clone();
        student2.subject2 = (Subject2) this.subject2.clone();
        return student2;
    }

    /* 深复制 二进制的写法,需要类序列化*/
    public Object deepClone() throws IOException, ClassNotFoundException {

        //使用序列化和反序列化实现深复制
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        byte[] bytes = bos.toByteArray();
        /* 读出二进制流产生的新对象 */
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }

    public static void main(String[] args) throws CloneNotSupportedException{
        Subject2 subject2= new Subject2("100","100");
        Student2 student2 = new Student2("YYY",subject2);
        System.out.println(student2);
        //方法一:对象内部所有引用型对象都进行clone。
        //Student2 st2 = (Student2)student2.clone();
        //方法二:对象序列化
        Student2 st2 = (Student2)student2.clone();
        st2.setName("ZZZ");
        st2.getSubject2().setChinese("99");
        System.out.println(student2);
        System.out.println(st2);
    }
}
class Subject2 implements Serializable, Cloneable {
    private String english;
    private String chinese;

    public Subject2(String chinese,String english){
        this.chinese = chinese;
        this.english = english;
    }

    @Override
    public String toString(){
        return "english : "+english+"; chinese:"+chinese;
    }
    @Override
    public Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
    public String getEnglish() {
        return english;
    }

    public void setEnglish(String english) {
        this.english = english;
    }

    public String getChinese() {
        return chinese;
    }

    public void setChinese(String chinese) {
        this.chinese = chinese;
    }
}

运行结果:

name:YYY; subject:{english : 100; chinese:100}
name:YYY; subject:{english : 100; chinese:100}
name:ZZZ; subject:{english : 100; chinese:99}

通过对引用类型值subject添加clone方法,并且对student对象的clone方法改造,实现深克隆。
JAVA设计模式之原型模式

4、其他:

拷贝还有2个知识点,对象拷贝时,类的构造函数是不会被执行的。一个实现了 Cloneable 并重写了 clone 方法的类 Programmer,有一个无参构造或有参构造 ,通过 new 关键字产生了一个对象 A,再然后通过 A.clone()方式产生了一个新的对象 T,那么在对象拷贝时构造函数是不会被执行的。即拷贝的过程中只执行一次构造方法。

Clone 与 final 两对冤家。对象的 clone 与对象内的 final 属性是由冲突.在上面的Programmer类中修改为private final Address address;去掉get,set方法, proto.address=(Address) address.clone();这一句就会报错: proto.address=(Address) address.clone();final类型不能重新设置值。解决办法就是删除掉fina咯

深拷贝和浅拷贝建议不要混合使用,一个类中某些引用使用深拷贝某些引用使用浅拷贝,这是一种非常差的设计,特别是是在涉及到类的继承,父类有几个引用的情况就非常的复杂,建议深拷贝和浅拷贝分开实现。

相关文章: