【Java设计模式】创建型设计模式-原型模式(五)

140 阅读5分钟

代码GitHub:github.com/lanjie6/Des…

原型模式

  • 原型模式指的是用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象,在这里。原型实例指定了要创建的对象的种类。
  • 用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,虚拟机CentOS操作系统的安装通常较耗时,如果克隆就快了很多。

进一步阐述:

  • 原型模式的克隆分为浅克隆和深克隆。
  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

原型模式包含的三种角色:

  • AbstractPrototype(抽象原型角色):规定了具体原型对象必须实现的接口。
  • ConcretePrototype(具体原型角色):实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • Visit(访问角色):使用具体原型类中的 clone() 方法来复制新的对象。

案例:用原型模式生成“三好学生”奖状为例,同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,属于相似对象的复制,然后再做简单修改就可以了。客户端Client类就是具体的访问角色,奖状Citation类,就是具体原型角色,JDK提供的Cloneable接口就是抽象原型角色。

UML类图:

原型模式.jpg

客户端Client类:

/**
 * 使用原型模式的客户端(访问角色)
 */
public class Client {
​
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建奖状原型
        Citation citation = new Citation("xx", "同学:在2021学年第一学期中表现优秀,被评为三好学生。", "成都学院");
​
        //克隆奖状,并写上每个同学的姓名
        Citation zhangSanCitation= (Citation) citation.clone();
        zhangSanCitation.setName("张三");
        zhangSanCitation.display();
​
        Citation liSiCitation= (Citation) citation.clone();
        liSiCitation.setName("李四");
        liSiCitation.display();
    }
}

奖状Citation类:

/**
 * 奖状类(具体原型角色)
 * 其中JDK提供的Cloneable接口就是抽象原型角色
 */
public class Citation implements Cloneable {
    /**
     * 获奖学生名字
     */
    String name;
​
    /**
     * 获奖信息
     */
    String info;
​
    /**
     * 学院
     */
    String college;
​
    public Citation(String name, String info, String college) {
        this.name = name;
        this.info = info;
        this.college = college;
        System.out.println("奖状创建成功!");
    }
​
    /**
     * 设置不同学生的奖状名字
     */
    public void setName(String name) {
        this.name = name;
    }
​
    /**
     * 陈列奖状信息的方法
     */
    public void display() {
        System.out.println(name + info + college);
    }
​
    /**
     * 重写克隆方法
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        System.out.println("奖状拷贝成功!");
        return super.clone();
    }
}

运行结果:

原型模式运行结果.png

总结:

  • Java自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
  • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
  • 需要为每一个类都配置一个 clone 方法,clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
  • 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。

典型运用场景举例:

  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。
  • 在 Spring 中,原型模式应用的非常广泛,例如 @scope("prototype")改为多例模式的时候,其实对象是基于原型模式克隆出来的多个对象,并非是New出来和反射出来的。

设计模式相关文章