模式导读:

     随着现代科技的进步,我们的生物技术已经差不多能够做到理论上的"重生",克隆羊多利的出现已经证实了这一点。同样的,在别的领域基本都有类似这样的情况,在有的公司里一周就要做一次报表,但是每一周的报表内容都差不多,每一次都得重复部分内容,这样大大的减少了效率,于是就有了报表的模板,只要根据不同情况选用不同的报表模板然后在此基础上修改部分内容就完成了,效率因此提高。这便是原型模式适用的场景,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

参考类图:

java设计模式-原型模式 随笔 第1张

 在原型模式结构图中包含如下几个角色:

      ●Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。

      ● ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。

      ● Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。由于客户类针对抽象原型类Prototype编程,因此用户可以根据需要选择具体原型类,系统具有较好的可扩展性,增加或更换具体原型类都很方便。

代码实现:

1.首先要有一个抽象的原型类,并且实现了Cloneable接口,在其中还定义有抽象方法用于具体原型子类克隆后的结果展示,同时实现接口的clone()方法

 1 package com.etc;
 2 //定义一个抽象原型类,实现抽象接口Cloneable类
 3 public abstract class Shape implements Cloneable {
 4     
 5     abstract void draw();
 6     //实现克隆方法返回克隆出来的新对象
 7     public  Shape clone(){
 8         Shape clone=null;
 9         try {
10             clone=(Shape) super.clone();
11         } catch (CloneNotSupportedException e) {
12             
13             e.printStackTrace();
14         }
15         return clone;
16     }
17 }

2.定义具体的原型类继承抽象原型父类,实现draw()方法将克隆结果展示出来

(1)Line.java

 1 package com.etc;
 2 //具体的原型类
 3 public class Line extends Shape {
 4 
 5     @Override
 6     void draw() {
 7         
 8         System.out.println("画出的形状为一条线");
 9     }
10 
11 }

(2)Circle.java

1 package com.etc;
2 //具体的原型类
3 public class Circle extends Shape {
4     
5     @Override
6     void draw() {
7         System.out.println("画出的形状为一个圆");
8     }
9 }

(3)Quare.java

 1 package com.etc;
 2 //具体的原型类
 3 public class Quare extends Shape{
 4 
 5     @Override
 6     void draw() {
 7         
 8         System.out.println("画出的形状一个方块");
 9     }
10 }

3.客户端类,选择克隆哪个具体原型类,将克隆结果打印出来

 1 package com.etc;
 2 /*
 3 Java语言提供的Cloneable接口和Serializable接口的代码非常简单,
 4 它们都是空接口,这种空接口也称为标识接口,标识接口中没有任何方法的定义,
 5 其作用是告诉JRE这些接口的实现类是否具有某个功能,如是否支持克隆、是否支持序列化等。
 6 */
 7 
 8 public class Client {
 9     //客户端可以根据情况需要对不同的具体原型类实现克隆
10     public static void main(String[] args) {
11         
12         Shape obj1=new Circle();
13         Shape ob1=obj1.clone();//将克隆出来的对象放到新的对象里面
14         //判断克隆出来的对象与原对象是否相同
15         System.out.println(obj1==ob1);
16         
17         Shape obj2=new Line();
18         Shape ob2=obj2.clone();
19         
20         Shape obj3=new Quare();
21         Shape ob3=obj3.clone();
22         //将克隆出来的对象进行打印
23         ob1.draw();
24         ob2.draw();
25         ob3.draw();
26         
27     }
28 
29 }

效果截图:

java设计模式-原型模式 随笔 第2张

由此可见,克隆出来的对象与原有对象并不是同一个对象。

原型模式优缺点:

1.主要优点

(1) 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率。

(2) 扩展性较好,由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程,而将具体原型类写在配置文件中,增加或减少产品类对原有系统都没有任何影响。

(3) 原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式就不需要这样,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品。

(4) 可以使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(如恢复到某一历史状态),可辅助实现撤销操作。

2.主要缺点

(1) 需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了“开闭原则”。

(2) 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。

适用场景:

(1) 创建新对象成本较大(如初始化需要占用较长的时间,占用太多的CPU资源或网络资源),新的对象可以通过原型模式对已有对象进行复制来获得,如果是相似对象,则可以对其成员变量稍作修改。

(2) 如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占用内存较少时,可以使用原型模式配合备忘录模式来实现。

(3) 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。

 ps:这篇文章纯属用于简单了解原型模式,并没有深入到深克隆,浅克隆技术上,现在还在作为小白学习中,大佬勿喷。

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄