当前位置: 首页 > 图灵资讯 > 技术篇> 23种设计模式——原型模式

23种设计模式——原型模式

来源:图灵教育
时间:2023-12-08 17:11:05

今天,我们将学习23种设计模式中的第五种原型模式。它主要用于创建重复对象,并确保系统的性能。让我们来看看这种设计模式的巧妙之处。

应用前景:

在我们的应用程序中,有些对象的结构可能很复杂,但我们需要经常使用它们。如果我们在这个时候不断地创建这个对象,我们必然会损失系统内存。此时,我们需要使用原型模式来克隆结构复杂且需要频繁使用的对象。因此,原型模式是用原型实例指定创建对象的类型,并通过复制这些原型创建新对象。

原型模式的概念:

以创建的实例为原型,复制原型对象,创建与原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的类型。这样创建对象是非常有效的,没有必要知道对象创建的细节。

原型模式的特点:

该模型的主要优点如下:

  • 性能提高。
  • 避免构造函数的约束。

主要缺点如下:

  • 配备克隆方法需要综合考虑类别的功能,这对于新类别来说并不难,但对于现有类别来说并不一定容易,特别是当一个类别引用不支持串行的间接对象时,或引用包含循环结构。
  • 必须实现 Cloneable 接口。
原型模式的主要作用:
  • 抽象原型类:规定了具体原型对象必须实现的接口。
  • 具体原型类别:实现抽象原型类别 clone() 该方法是可复制的对象。
  • 访问类别:在特定的原型类别中使用 clone() 复制新对象的方法。
代码:

1.克隆羊问题的传统方式

image.png

总结:

  • 优点是易于理解,操作简单方便。
  • 在创建新的对象时,总是需要重新获得原始对象的属性,如果创建的对象更复杂,效率更低。
  • 总是需要重新初始化对象,而不是动态获得对象运行时的状态,这是不够灵活的。

2.克隆羊问题在原型模式下:

浅拷贝:

介绍浅拷贝:

  • 对于数据类型是基本数据类型的成员变量,浅拷贝将直接传递值,即将属性值复制给新对象。
  • 对于数据类型是参考数据类型的成员变量,如成员变量是一个数组,一个类别的对象,然后浅复制将被引用和传输,即只复制成员变量的参考值(内存地址)到一个新的对象。因为事实上,两个对象的成员变量都指向同一个例子。在这种情况下,在一个对象中修改成员变量会影响另一个对象中成员变量的值。
  • 下面我们说的克隆羊其实是浅拷贝,浅拷贝是默认的clone()实现方法,sheep = (Sheep) super.clone();

克隆羊原型(Sheep)

package cn.ppdxzz.prototype.shallowclone;/** * Description:克隆羊原型 */public class Sheep implements Cloneable {    private String name;//姓名    private int age;//年龄    private String color;//颜色    private String type = "蒙古羊";//种类    public Sheep(String name, int age, String color) {        super();        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 + '\'' +                ", type='" + type + '\'' +                '}';    }    //克隆这个例子,使用默认的clone方法来完成    @Override    protected Object clone() {        Sheep sheep = null;        try {            sheep = (Sheep)super.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        return sheep;    }}

克隆羊的原型模式

package cn.ppdxzz.prototype.shallowclone;/** * Description:克隆羊的原型模式 */public class Client {    public static void main(String[] args) {        Sheep sheep = new Sheep("多利",1,"白色");        Sheep sheep1 = (Sheep)sheep.clone();//克隆        Sheep sheep2 = (Sheep)sheep.clone();//克隆        Sheep sheep3 = (Sheep)sheep.clone();//克隆        System.out.println("sheep1 = "+ sheeep1);        System.out.println("sheep2 = "+ sheeep2);        System.out.println("sheep3 = "+ sheep3);    }}

深拷贝:

深拷贝介绍:

  • 复制对象所有基本数据类型的成员变量值。
  • 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量引用的对象,直到对象可以到达所有对象。也就是说,对象应该复制整个对象。

实现深拷贝的方法:

  • 方法一:重写clone方法,实现深度复制。

  • 方法二:深拷贝(推荐使用这种深拷贝)是通过对象序列化实现的。

需要深度复制的对象

package cn.ppdxzz.prototype.deepclone;import java.io.Serializable;/** * Description:要深度复制一个对象 */public class DeepCloneClass implements Cloneable, Serializable {    private String cloneName;/////深拷贝对象的名称    private String cloneDescription;////深拷贝对象的描述    public DeepCloneClass() {    }    public DeepCloneClass(String cloneName, String cloneDescription) {        this.cloneName = cloneName;        this.cloneDescription = cloneDescription;    }    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}

深度复制原型对象(包括引用数据类型)

package cn.ppdxzz.prototype.deepclone;import java.io.*;/** * Description:深度复制原型对象(包括引用数据类型) */public class DeepPrototype implements Cloneable, Serializable {    private String name;///String类型    private DeepCloneClass deepCloneClass;//引用数据类型,对象进行深度复制    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public DeepCloneClass getDeepCloneClass() {        return deepCloneClass;    }    public void setDeepCloneClass(DeepCloneClass deepCloneClass) {        this.deepCloneClass = deepCloneClass;    }    ///方法一实现深拷贝    @Override    protected Object clone() throws CloneNotSupportedException {        Object deep = null;        //1.在这里复制基本数据类型和String类型        deep = super.clone();        //2.单独处理引用数据类型的数据        DeepPrototype deepPrototype = (DeepPrototype) deep;        deepPrototype.setDeepCloneClass((DeepCloneClass)deepCloneClass.clone());        return deepPrototype;    }    //方法二实现深拷贝    public Object deepClone() {        //1.创建流对象        ByteArrayOutputStream bos = null;        ObjectOutputStream oos = null;        ByteArrayInputStream bis = null;        ObjectInputStream ois = null;        try {            //2.序列化            bos = new ByteArrayOutputStream();            oos = new ObjectOutputStream(bos);            oos.writeObject(this);            //3.反序列化            bis = new ByteArrayInputStream(bos.toByteArray());            ois = new ObjectInputStream(bis);            DeepPrototype copyObj = (DeepPrototype) ois.readObject();            return copyObj;        } catch (Exception e) {            e.printStackTrace();            return null;        }        finally {            //4.关闭流量            if (oos != null) {                try {                    oos.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if (ois != null) {                try {                    ois.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

客户端验证是否可以进行深度复制

package cn.ppdxzz.prototype.deepclone;/** * Description:客户端 */public class Client {    public static void main(String[] args) throws Exception {        DeepPrototype d = new DeepPrototype();        d.setName("深拷贝");        d.setDeepCloneClass(new DeepCloneClass("深拷贝对象","我需要深度复制的对象"));        //1.方法一完成深拷贝        DeepPrototype dClone = (DeepPrototype) d.clone();        System.out.println("原型.name = " + d.getName() + " 原型.deepCloneClass = " + d.getDeepCloneClass().hashCode());        System.out.println("克隆.name = " + dClone.getName() + " 克隆.deepCloneClass = " + dClone.getDeepCloneClass().hashCode());        //2.方法2完成深拷贝        DeepPrototype dClone = (DeepPrototype)d.deepClone();        System.out.println("原型.name = " + d.getName() + " 原型.deepCloneClass = " + d.getDeepCloneClass().hashCode());        System.out.println("克隆.name = " + dClone.getName() + " 克隆.deepCloneClass = " + dClone.getDeepCloneClass().hashCode());    }}
原型模式源码分析:

Spring中原型bean的创建是使用的原型模式 。

image.png

总结:
  • 当创建新对象更加复杂时,可以使用原型模式来简化对象的创建过程,同时也可以提高效率。
  • 动态获取对象运行时的状态,而不是重新初始化对象。
  • 如果原始对象发生变化(增加或减少属性),其他克隆对象也会发生相应的变化,无需修改代码。
  • 可能需要更复杂的代码来实现深克隆。
  • 注:它需要为每个类配备一种克隆方法,这对新类来说并不难,但在改造现有类时,需要修改其源代码,这是违反的OCP原则。

到目前为止,已经完成了创造性的五种设计模式,即单例模式、工厂方法模式、抽象工厂模式、建筑商模式和原型模式。下一阶段,我们将开始学习结构设计模式。请期待它。