原型模式

Posted hhhshct

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原型模式相关的知识,希望对你有一定的参考价值。

  原型模式定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

  在JAVA语言中使用原型模式是非常简单的,这是因为Object类当中提供了一个本地方法clone,而JAVA中的任何类只要实现了Cloneable标识接口,就可以使用clone方法来进行对象的拷贝。

  从原型模式的使用方式不难推断出,原型模式常使用于以下场景:

  1、对象的创建非常复杂,可以使用原型模式快捷的创建对象。
  2、在运行过程中不知道对象的具体类型,可使用原型模式创建一个相同类型的对象,或者在运行过程中动态的获取到一个对象的状态。

  由于clone方法是由虚拟机直接复制内存块执行,所以在速度上比使用new的方式创建对象要快,并且在拷贝对象时不会执行对应类的构造方法。

  提到原型模式,就不得不提浅拷贝和深拷贝。浅拷贝是指将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。深拷贝将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制。

  下面我们来看一个浅拷贝的例子

package prototype;

public class Student {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    
}
package prototype;

public class Family implements Cloneable{

    private String address;
    private Student student;
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public Student getStudent() {
        return student;
    }
    public void setStudent(Student student) {
        this.student = student;
    }
    public Family clone() {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return (Family) obj;
    }
}

  编写测试代码,结果如下:

技术分享图片

  可以看到我们copy得来的对象fa2中持有的Student实例和fa中的是一个,所以当我们对fa2中student对象进行修改时,会影响到原来的fa,那么如何实现深拷贝呢?有两种方式。

  1、要实现深度拷贝,则需要将实现了Cloneable接口并重写了clone方法的类中,所有的引用类型也全部实现Cloneable接口并重写clone方法,而且需要将引用类型的属性全部拷贝一遍。

  修改Student和Fimaly类如下

package prototype;

public class Student implements Cloneable{
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student clone() {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return (Student) obj;
    }
}
package prototype;

public class Family implements Cloneable{

    private String address;
    private Student student;
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public Student getStudent() {
        return student;
    }
    public void setStudent(Student student) {
        this.student = student;
    }
    public Family clone() {
        Object obj = null;
        try {
            obj = super.clone();
            ((Family)obj).setStudent(this.student.clone());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return (Family) obj;
    }
}

  执行测试代码如下:

技术分享图片

  2、利用序列化,我们的目标类要实现Serializable接口

  修改Student和Fimaly类如下

package prototype;

import java.io.Serializable;

public class Student implements Serializable{
    private static final long serialVersionUID = -3865833738045253326L;
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
}
package prototype;

import java.io.Serializable;

public class Family implements Serializable{

    private static final long serialVersionUID = 7498435126824884787L;
    private String address;
    private Student student;
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public Student getStudent() {
        return student;
    }
    public void setStudent(Student student) {
        this.student = student;
    }
}

  测试类

package prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Client2 {

    public static Family depCopy(Family fa) {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        try {
            ObjectOutputStream out = new ObjectOutputStream(byteOut);
            out.writeObject(fa);
 
            ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
            ObjectInputStream inStream = new ObjectInputStream(byteIn);
            Family fa2 = (Family) inStream.readObject();
            return fa2;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args) {
        Student stu = new Student("张三", 12);
        Family fa = new Family();
        fa.setAddress("北京");
        fa.setStudent(stu);
        Family fa2 = depCopy(fa);
        System.out.println(fa2.getStudent() == fa.getStudent());
    }
}

  结果自然是false,就不再贴出了。

  


以上是关于原型模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之原型模式(Prototype)详解及代码示例

设计模式课程 设计模式精讲 9-2 原型模式coding

设计模式--原型模式

5.原型模式

设计模式原型模式

csharp 设计模式 - 原型 - 结构代码