跳到主要内容

原型模式

原型模式

  • 原型模式(Prototype 模式)是指用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
    原型模式是一种创建型模式,允许一个对象再创建另一个可定制的对象,无需知道如何创建的细节

  • 工作原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝他们自己来实施创建,即 对象.clone()

  • 原型模式类图实例
    原型模式类图实例

    1. Prototype:原型类,声明一个克隆自己的接口
    2. ConcretePrototype:具体的原型类,实现一个克隆自己的操作
    3. Client:让一个原型对象克隆自己,从而创建一个新对象(属性一样)
  • 代码实例
    Sheep 类实现 Cloneable 接口重写 clone 方法

    public class Sheep implements Cloneable{

    private String name;
    private int age;
    private String color;

    public Sheep(String name, int age, String color) {
    this.name = name;
    this.age = age;
    this.color = color;
    }

    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 String getColor() {
    return color;
    }

    public void setColor(String color) {
    this.color = color;
    }

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

    //克隆该实例,使用默认的clone方法来完成
    @Override
    protected Object clone() {
    Sheep sheep = null;
    try {
    sheep = (Sheep) super.clone();
    } catch (Exception e) {
    System.out.println(e.getMessage());
    }
    return sheep;
    }
    }

    Client 类测试创建多个 Sheep 的实例,查看状态是否一致

    public class Client {
    public static void main(String[] args) {
    System.out.println("原型模式完成对象的创建");
    Sheep sheep=new Sheep("tom",1,"白色");
    Sheep sheep2=(Sheep)sheep.clone();
    Sheep sheep3=(Sheep)sheep.clone();
    Sheep sheep4=(Sheep)sheep.clone();
    System.out.println("sheep2: "+sheep2);
    System.out.println("sheep3: "+sheep3);
    System.out.println("sheep4: "+sheep4);

    }
    }
  • Spring 中原型 Bean 的创建,就是原型模式的应用

深拷贝与浅拷贝

浅拷贝

  • 单纯使用 clone 即 super.clone() 创建一个新对象,新对象的属性和原对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址,当修改对象中非基本类型属性的值时,新对象中的属性也会发生变化,是一个非常严重的安全问题
  • 总结:只会复制对象的值类型,不会复制对象的引用类型
  • 代码实例
    //克隆该实例,使用默认的clone方法来完成
    @Override
    protected Object clone() {
    Sheep sheep = null;
    try {
    sheep = (Sheep) super.clone();
    } catch (Exception e) {
    System.out.println(e.getMessage());
    }
    return sheep;
    }

深拷贝

  • 复制整个对象,包括值类型和引用类型
  • 实现方式有序列化实现和重写 clone 方法两种

序列化实现(推荐)

  • 实现思路:先将原对象序列化到内存的字节流中,再从字节流中反序列化出刚刚存储的对象,新对象与原对象不存在任何地址上的共享,就完成了深克隆

  • 类需要实现 Serializable 接口

  • 代码示例

    //深拷贝 - 通过对象序列化实现(推荐使用)
    // DeepCloneableTarget类
    public class DeepCloneableTarget implements Serializable, Cloneable {
    private static final long serialVersionUID = 1L;
    private String cloneName;
    private String cloneClass;

    public DeepCloneableTarget(String cloneName, String cloneClass) {
    this.cloneName = cloneName;
    this.cloneClass = cloneClass;
    }
    //因为该类的属性,都是String,因此我们这里使用默认的clone完成即可.
    @Override
    protected Object clone() throws CloneNotSupportedException {
    return super.clone();
    }
    }

    // DeepProtoType 类
    public class DeepProtoType implements Serializable, Cloneable {

    public String name;
    public DeepCloneableTarget deepCloneableTarget;

    public DeepProtoType() {
    super();
    }

    // 克隆实现
    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);
    DeepProtoType copyObj = (DeepProtoType) ois.readObject();
    return copyObj;
    } catch (Exception e) {
    e.printStackTrace();
    return null;
    } finally {
    try {
    bos.close();
    oos.close();
    bis.close();
    ois.close();
    } catch (Exception e2) {
    e2.printStackTrace();
    }
    }
    }
    }

重写 clone 方法

  • 所有引用类型都实现克隆

  • 代码示例

    //深拷贝 - 使用clone 方法
    // DeepCloneableTarget 方法
    public class DeepCloneableTarget implements Serializable, Cloneable {
    private static final long serialVersionUID = 1L;
    private String cloneName;
    private String cloneClass;
    public DeepCloneableTarget(String cloneName, String cloneClass) {
    this.cloneName = cloneName;
    this.cloneClass = cloneClass;
    }

    //因为该类的属性,都是String,因此我们这里使用默认的clone完成即可.
    @Override
    protected Object clone() throws CloneNotSupportedException {
    return super.clone();
    }
    }

    // DeepProtoType类
    public class DeepProtoType implements Serializable, Cloneable {
    public String name;
    public DeepCloneableTarget deepCloneableTarget;
    public DeepProtoType() {
    super();
    }

    // 克隆实现
    @Override
    protected Object clone() throws CloneNotSupportedException {
    Object deep = null;
    //完成对基本数据类型(属性)和String的克隆
    deep = super.clone();
    //对引用类型的属性,进行单独的处理。
    DeepProtoType deepProtoType = (DeepProtoType) deep;
    deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();

    return deep;
    }
    }

注意事项和细节

  1. 创建新的对象比较复杂时,可以通过原型模式简化对象的创建过程,提高效率
  2. 不用重新初始化对象,而是动态地获取对象运行时的状态
  3. 如果原始对象发生变化(增加/减少属性),其他克隆对象也会发生相应的变化,无需修改代码
  4. 缺点是需要为每一个类配备一个克隆方法