原型模式(Prototype Pattern),用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象;即用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

在运行期建立和删除原型;利用一个已有的原型对象,快速的生成和原型对象一样的实例;

使用场景:

1、当一个系统应该独立于它的产品创建,构成和表示时。
2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。
3、为了避免创建一个与产品类层次平行的工厂类层次时。
4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

实例解析:

原型类以及具体原型实现类的代码在这里就不在列出了,详情请看上面的类图;

创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。

ShapeCache.java

import java.util.Hashtable;public class ShapeCache {private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>();public static Shape getShape(String shapeId) {Shape cachedShape = shapeMap.get(shapeId);//返回一个shapeId对应的Shape的克隆对象,注意Shape类要实现Cloneable接口return (Shape) cachedShape.clone();}// 简化操作:不查数据库了,直接后台添加三种形状public static void loadCache() {Circle circle = new Circle();circle.setId("1");shapeMap.put(circle.getId(),circle);Square square = new Square();square.setId("2");shapeMap.put(square.getId(),square);Rectangle rectangle = new Rectangle();rectangle.setId("3");shapeMap.put(rectangle.getId(),rectangle);}
}

PrototypePatternDemo 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

PrototypePatternDemo.java

public class PrototypePatternDemo {public static void main(String[] args) {ShapeCache.loadCache();Shape clonedShape = (Shape) ShapeCache.getShape("1");System.out.println("Shape : " + clonedShape.getType());       Shape clonedShape2 = (Shape) ShapeCache.getShape("2");System.out.println("Shape : " + clonedShape2.getType());      Shape clonedShape3 = (Shape) ShapeCache.getShape("3");System.out.println("Shape : " + clonedShape3.getType());      }
}

输出结果:

Shape : Circle
Shape : Square
Shape : Rectangle

实现的关键:

1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone() 方法来实现对象的浅复制或通过序列化(serializable)的方式来实现深复制

2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些”易变类”拥有稳定的接口。

原型模式的优点:

通过普通的new方式实例化对象时,每new一次就需要执行一次构造函数,如果构造函数的执行时间很长,那么多次执行程序效率就会大打折扣;一般在初始化的信息不发生变化的情况下,克隆是最好的办法,这既隐藏了对象的创建细节,又大大提升了性能。

浅复制 VS 深复制

以大话设计模式里面的一个经典的简历的例子来学习这两个概念:

浅复制

WorkExperience.java

public class WorkExperience{private string workDate;private string company;public string workDate(){//getter and setter}public string company(){//getter and setter}
}

Resume.java

public class Resume implements ICloneable{private string name;private string sex;private string age;private WorkExperience work;//引用工作经历对象//构造函数public Resume(string name){this.name = name;work = new WorkExperience();}//设置个人信息public void setPersonalInfo(String sex,String age){this.sex = sex;this.age = age;}//设置工作经历public void setWorkExperience(String timeArea,String company){work.timeArea = timeArea;work.company = company;}//显示public void display(){System.out.println("姓名:" + name + " 性别:" + sex + " 年龄:" + age);”System.out.println("工作经历:" + work.timeArea +" " + company);}//克隆方法public Object Clone(){return (Object)this.MemberwiseClone();}}

测试类:

public class TestPrototype{public satic void main(String[] args){Resume resumeOne =  new Resume( "tom");  resumeOne.SetPersonalInfo( "man","22");  resumeOne.SetWorkExperience( "2015-1-2至2015-12-10","IBM");  Resume resumeTwo = (Resume)resumeOne.Clone();        resumeTwo.SetWorkExperience( "2015-1-2至2015-11-11","Microsoft");  Resume resumeThree = (Resume)resumeOne.Clone();  resumeThree.SetPersonalInfo( "man",  "32");  resumeThree.SetWorkExperience( "2015-1-2至2015-11-11","甲骨文");  resumeOne.Display();  resumeTwo.Display();  resumeThree.Display();  Console.Read();  } }

在你的想象里输出结果会是什么呢?我们拿事实来说话:

姓名:tom 性别:man 年龄:22
工作经历:2015-1-2至2015-11-11 甲骨文
姓名:tom 性别:man 年龄:22
工作经历:2015-1-2至2015-11-11 甲骨文
姓名:tom 性别:man 年龄:32
工作经历:2015-1-2至2015-11-11 甲骨文

看到结果有没有很惊讶,对于工作经历的输出相信出乎了好多人的意料,这个地方我们就要说到MemberwiseClone()这个方法了,(有关MemberwiseClone的详细内容请参见本人的另一篇文章

深复制VS浅复制(MemberwiseClone方法介绍)

),其对于值类型没有问题,但是对于引用类型,就只是复制了引用,对引用对象还是指向了原来的对象,所以就会出现我们给resume one two three三处设置工作经历,但却得到三个引用都是最后一次的设置,这是因为三个引用都指向了同一对象。

那么问题来了,到底什么是浅复制呢?

浅复制:被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。

然而我们希望实现的是一变二,二变三,我么叫这种方式为深复制:把引用对象的变量指向复制过的新对象,而不是原来的被引用的对象。(使用深复制要注意避免循环引用的问题)

深复制如何实现这个例子呢?简历类和工作经历类都实现了ICloneable接口;

WorkExperience.java

public class WorkExperience implements ICloneable{private string workDate;private string company;public string workDate(){//getter and setter}public string company(){//getter and setter}//克隆方法public Object Clone(){return (Object)this.MemberwiseClone();}
}

Resume .java

public class Resume implements ICloneable{private string name;private string sex;private string age;private WorkExperience work;//引用工作经历对象//构造函数public Resume(string name){this.name = name;work = new WorkExperience();}//注意这个构造方法private Resume(WorkExperience work){this.work = work.(WorkExperience)clone;}//设置个人信息public void setPersonalInfo(String sex,String age){this.sex = sex;this.age = age;}//设置工作经历public void setWorkExperience(String timeArea,String company){work.timeArea = timeArea;work.company = company;}//显示public void display(){System.out.println("姓名:" + name + "性别:" + sex + "年龄:" + age);System.out.println("工作经历:" + work.timeArea + company);}//注意区别该类实现的克隆方法与浅复制时实现的克隆方法的区别public Object Clone(){//调用私有的构造方法克隆工作经历,然后再给建立对象赋值Resume resume = new Resume(this.work);resume.name = this.name;resume.sex = this.sex;resume.age = this.age;}}

测试类同上,这次输出结果会是什么呢?

姓名:tom 性别:man 年龄:22
工作经历:2015-1-2至2015-12-10 IBM
姓名:tom 性别:man 年龄:22
工作经历:2015-1-2至2015-11-11 Microsoft
姓名:tom 性别:man 年龄:32
工作经历:2015-1-2至2015-11-11 甲骨文

由于在一些特定场合,会经常涉及深复制和浅复制,比如说,数据集对象DataSet,他就有Clone()和copy()方法,Clone()方法用来复制DataSet的结构但不复制其数据,实现了原型模式中的浅复制;而copy()方法不但复制其结构还复制其数据,也就是实现了原型模式中的深复制

大话设计模式—原型模式相关推荐

  1. 大话设计模式-原型模式的浅复制与深复制

    在看这个原型模式的时候,不知你是否有和博主一样的迷茫.诶,这里不是复制对象,怎么改属性并不是全部对象都改

  2. linkin大话设计模式--常用模式总结

    linkin大话设计模式--常用模式总结 一,常用设计模式定义 Abstract Factory(抽象工厂模式):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. Adapter( ...

  3. 设计模式 原型模式_创新设计模式:原型模式

    设计模式 原型模式 原型模式用于创建对象的副本. 这种模式非常有用,特别是当从头开始创建对象的成本很高时. 与builder , factory和abstract factory模式相比,它不会从头开 ...

  4. 设计模式 原型模式_设计模式:原型

    设计模式 原型模式 创新设计模式之一是原型设计模式 . 尽管原型是创造模式,但它在概念上与其他模式有所区别. 我的意思是原型在某种意义上创造了自己. 我将在下面解释. 原型模式的所有魔力都基于Java ...

  5. 设计模式 原型模式_原型设计模式:创建另一个小车

    设计模式 原型模式 创建对象确实是一个耗时的过程,也是一件昂贵的事情. 因此,我们现在正冒险节省时间和金钱. 我们该怎么做? 克隆奇迹多莉 有人记得多莉吗? 是的,是绵羊,是第一个被克隆的哺乳动物. ...

  6. Java常用设计模式————原型模式(一)

    介绍 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. 原型模式用于创建重复的对象,同时又能保证性能.当直接创建对象的代价比较大时,则采用 ...

  7. 第六章 Caché 设计模式 原型模式

    文章目录 第六章 Caché 设计模式 原型模式 定义 使用场景 优点 结构图 描述 示例 初级写法 缺点 中级写法 缺点 高级写法 (浅复制) 浅复制 深复制 完整示例 简历类(复制类) 对象类(工 ...

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

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

  9. linkin大话设计模式--桥接模式

    linkin大话设计模式--桥接模式 桥接模式是一种结构化模式,他主要应对的是:由于实际的需要,某个类具有2个或者2个以上维度的变化,如果只是使用继承将无法实现功能,或者会使得设计变得相当的臃肿.我们 ...

最新文章

  1. backup(full,diff,log)备份并清理过时备份
  2. 鸿蒙投屏和普通投屏,华为智慧屏SE发布:预装鸿蒙 可一碰投屏
  3. 我的R之路:参数假设检验
  4. opencv求两张图像光流_OpenCV单应性矩阵发现参数估算方法详解
  5. 《SaltStack技术入门与实践》—— Job管理
  6. 怎么在linux的cmd中运行c项目,如何在cmd窗口编译运行c语言程序?
  7. creo动画如何拖动主体_Animate如何制作动态遮罩文字动画
  8. IE8下强制浏览器用哪个IE版本渲染页面
  9. mysql 忘记密码处理方式
  10. linux下以RPM方式安装MySQL5.5
  11. Crypto.com APP上线The Graph(GRT)
  12. slope one算法matlab,求助我这个寻峰算法该怎么提高灵敏度
  13. python实践gcForest模型对鸢尾花数据集iris进行分类
  14. 使用postman下载文件
  15. 【学习笔记】InformationTheory——熵,条件熵,联合熵,互信息,交叉熵
  16. 申请免费SSL证书(阿里云)
  17. kubectl describe命令详解
  18. (项目)在线教育平台(九)
  19. 一起做RGB-D SLAM(3)
  20. swing入门教程(二) 简单的swing小部件

热门文章

  1. 第三方控件radupload 使用方式以及报错处理
  2. 高职学生如何成为编程高手
  3. Android 顶部滑动切换实现(一)
  4. innodb Cardinality学习笔记
  5. RabbitMQ,RabbitMQ 的工作模式,Spring 整合 RabbitMQ,Springboot 整合RabbitMQ
  6. SDNU 1178.能量项链(区间dp)
  7. Leetcode643.Maximum Average Subarray I子数组的最大平均数1
  8. 基于NEO的私链(Private Blockchain)
  9. list1与list2求交集的方法总结!
  10. 【TweenMax】实例TimelineMax