概念定义

使用原型实例指定待创建对象的种类,并通过拷贝该原型来创建新的对象。Prototype模式允许一个原型对象克隆(复制)出多个与其相同的对象,而无需知道任何如何创建的细节。

应用场景

  • 对象的创建过程较为复杂且需要频繁创建
  • 期望根据现有的实例来生成新的实例,例如:
    • 对象种类繁多而无法整合到一个类时
    • 难以通过指定类名生成实例时
    • 希望解耦框架与生成的实例时

在实际应用中,Prototype模式很少单独出现。经常与其他模式混用。

原型实现

所有Java类都继承自java.lang.Object,而Object类提供clone()方法来克隆对象。因此,Java类实现Cloneable接口并重写clone()方法后,即可实现Prototype模式

实现Prototype模式的示例代码如下:

// 原型类(也可定义为interface Prototype extends Cloneable)
abstract class Prototype implements Cloneable {private String name;public void setName(String name) {this.name = name;}public String getName() {return this.name;}public abstract void doSomething();@Overridepublic Object clone() { // clone()方法用public修饰Object object = null;try {object = super.clone(); // 调用父类clone()方法} catch (CloneNotSupportedException e) {e.printStackTrace();}return object;}
}// 具体实现类(继承自Prototype类自动具有克隆功能)
class ConcretePrototype extends Prototype{public ConcretePrototype() { setName("ConcretePrototype"); }@Overridepublic void doSomething() { System.out.println("I'll clone myself!"); }
}public class PrototypeDemo {public static void main(String[] args) {ConcretePrototype cp = new ConcretePrototype();cp.doSomething();for(int i=0; i< 5; i++){ConcretePrototype cloned = (ConcretePrototype)cp.clone();System.out.println("I'm cloned by " + cloned.getName());}}
}

执行后输出如下:

I'll clone myself!
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype

模式优缺点

Prototype模式的优点如下:

  • 根据客户端要求实现运行时动态创建对象,客户端不需要知道对象的创建细节,便于代码的维护和扩展。
  • 当对象的创建较为复杂或重复创建大量相似对象时,可简化对象创建,且性能比直接new对象更高(new会自动调用构造链中的所有构造方法,但clone不会调用任何类构造方法)。
  • Prototype模式类似工厂模式,但没有工厂模式中的抽象工厂和具体工厂的层级关系,代码结构更清晰和简单。

缺点如下:

  • 需要为每个类实现Cloneable接口并重写clone()方法,改造已有类时必须修改其源码,违背"开闭原则"。
  • 单例模式与工厂模式、Prototype模式是冲突的,尽量不要混用。
  • 在实现深拷贝(深克隆)时需要编写较为复杂的代码。

注意事项

clone()方法只拷贝对象中的基本数据类型,而不会拷贝数组、容器对象、引用对象等。若要实现深拷贝,必须将Prototype模式中的数组、容器对象、引用对象等另行拷贝
例如,深拷贝一个对象时,该对象必须实现Cloneable接口并重写clone()方法,并在clone()方法内部将该对象引用的其他对象也克隆一份。同理,被引用的对象也要做同样的处理。
注意,Boolean、Byte、Character、Class、Double、Float、Integer、Long、Short、String以及大部分的Exception的子类均为不可变类,其对象没有必要实现深拷贝。此外,大部分的Java容器类都已实现克隆功能。

相较而言,clone()方法更适合数组深拷贝。但需要注意以下两点:

(1) 基本类型的一维数组可通过诸如(int[])data.clone()的形式克隆,而基本类型的"二维数组"(实际上是类型诸如int[]的一维数组)需要按维克隆。例如:

public static int[][] twoDimensionArrayClone (int[][] tdArray){int[][] copy = tdArray.clone();for (int i = 0; i < tdArray.length; i++) {copy[i] = tdArray[i].clone();}return copy;
}

(2) 当数组元素为普通Java对象时,克隆数组后还要克隆数组中包含的对象。以下示例详细展示了数组对象的不同浅拷贝和深拷贝方式:

class Person implements Cloneable {public String name;public Person(String name) {this.name = name;}@Overridepublic Object clone() {Object object = null;try {object = super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return object;}
}public class ArrayPrototype {public static void main(String[] args) {Person[] origin = new Person[] { new Person("Mike"), new Person("Jack"), new Person("Jason") };Person[] copyOf = Arrays.copyOf(origin, origin.length);// 浅拷贝(内部调用System.arraycopy,返回新数组)Person[] arrayCopy = new Person[origin.length];// 浅拷贝(可拷贝部分数组)System.arraycopy(origin, 0, arrayCopy, 0, origin.length);Person[] clonedCopy = origin.clone();// 浅拷贝System.out.println("origin=copyOf=arrayCopy=clonedCopy="+ (origin[0] == copyOf[0] && copyOf[1] == arrayCopy[1] && arrayCopy[2] == clonedCopy[2]));clonedCopy[0].name = "Lily";System.out.println("Shallow Person[0]: " + origin[0].name + " -> " + clonedCopy[0].name);Person[] deepCopy = new Person[origin.length];// 深拷贝for (int i = 0; i < origin.length; i++) {deepCopy[i] = (Person) origin[i].clone();}deepCopy[1].name = "Lily";System.out.println("Deep Person[1]: " + origin[1].name + " -> " + clonedCopy[1].name);Person[] deepCopy2 = Arrays.stream(origin).map(Person::clone).toArray(Person[]::new);// 深拷贝deepCopy2[2].name = "Lucy";System.out.println("Deep Person[2]: " + origin[2].name + " -> " + deepCopy2[2].name);}
}

业界实践

  • Action对象(Struts2)
  • prototype创建的bean实例(Spring)

设计模式(14)——原型模式(Prototype)相关推荐

  1. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    [索引页] [源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:webabcd 介绍 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象. ...

  2. 设计模式之原型模式(Prototype)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式包括:1.FactoryMethod(工厂方法模式):2.Abstract Factory(抽象工厂模式):3.Sin ...

  3. 设计模式之原型模式prototype

    1.原型模式的使用和本质.以及优势: a.通过 new 产生一个对象需要非常繁琐的数据准备或者访问权限,则可以使用原型模式. b.原型模式的使用就是 java 中的克隆技术,以某个对象为原型,复制出新 ...

  4. 【设计模式】—— 原型模式Prototype

    前言:[模式总览]----------by xingoo 模式意图 由于有些时候,需要在运行时指定对象时哪个类的实例,此时用工厂模式就有些力不从心了.通过原型模式就可以通过拷贝函数clone一个原有的 ...

  5. 温故而知新:设计模式之原型模式(Prototype)

    原型模式个人以为最适合的场景:参照现有的某一个对象实例,快速得到多个完整的实例副本.(通常是深拷贝的副本) 深拷贝在c#中实现的最简单方式莫过于通过反序列化得到一个全新的对象实例.(当然如果浅拷贝的话 ...

  6. java prototype是什么,java设计模式-原型模式(Prototype)

    定义 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象.这就是原型模式的用意 原型模式的结构 原型模式要求对象实现同一个可 ...

  7. 设计模式五: 原型模式(Prototype)

    简介 原型模式是属于创建型模式的一种,是通过拷贝原型对象来创建新的对象. 万能的Java超类Object提供了clone()方法来实现对象的拷贝. 可以在以下场景中使用原型模式: 构造函数创建对象成本 ...

  8. C++设计模式——原型模式(Prototype Pattern)

    C++设计模式--原型模式(Prototype Pattern) 微信公众号:幼儿园的学霸 目录 文章目录 C++设计模式--原型模式(Prototype Pattern) 目录 定义 代码示例 普通 ...

  9. 设计模式(23):创建型-原型模式(Prototype)

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...

  10. C#设计模式(6)——原型模式(Prototype Pattern)

    一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在 ...

最新文章

  1. (0096)iOS开发之应用间的分享系列(1)
  2. Python程序的函数和代码复用
  3. 中序遍历的模板(以及变形更新中。。。)
  4. android string数组转json_移动端开发基础【20】pages.json的配置项pages
  5. android中给TextView或者Button的文字添加阴影效果
  6. linux查看服务状态
  7. 扩展jquery scroll事件,支持 scroll start 和 scroll stop
  8. 1分钟获取上千ID,暴力破解、端口扫描、拖库攻击如何防范
  9. 【微弱瞬态信号检测】混沌背景下微弱瞬态信号的SVM检测方法的matlab仿真
  10. python编程输入名字配对情侣网名_输入名字查另一半名字,怎样用一半情侣网名查...
  11. 【Java SE】数组
  12. hdu1175连连看
  13. 汽车研发的五大阶段及制造的四大工艺
  14. 学一点django基础
  15. ROLAP vs MOLAP vs HOLAP
  16. thinkpade450装内存条_Thinkpad e450c我想加一个内存条,因为开机就满了百分50左右,该加什么样的内存条?低电...
  17. Cryptographic nonce
  18. html普通文本和段落文本,HTML --- 网页文本与段落信息组织
  19. DTOJ#5238. 庆生会
  20. mysql 中文乱码问题解决(复制粘贴就可以解决)

热门文章

  1. 计算机中的bit byte(B) mb gb 的关系
  2. Mac 下 Eclipse 添加 Dynamic Web Project 并配置 Tomcat
  3. 模拟登陆github
  4. 856. Score of Parentheses
  5. Java线程池 与Lambda
  6. eclipse后台提示computing additional info的解决办法
  7. Hadoop1.2.0开发笔记(九)
  8. 获取Excel数据及Sheet的方法
  9. 【转】JAVA成长之路
  10. Rainbow分页解决方案