原型模式(Prototype Pattern)

原型模式主要用于创建重复的对象,同时又能保证性能,所以是创建型


在使用原型模式时,我们需要首先创建一个原型对象,再通过复制这个原型对象,来创建更多同类型的对象。

使用原型复制对象,性能很高,所以常用于创建大对象,或者初始化繁琐的对象:比如游戏里面的地图等等。

适用场景:

  • 一是类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等;

  • 二是通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式;

  • 三是一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。

注意:原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone的方法创建一个对象,然后由工厂方法提供给调用者。

UML的相关知识,可以访问我的另外一篇博文

网上的接口继承的方式实现起来较为简单:
通过ClassA implements Cloneable ,然后加入clone()方法即可【但是这是 浅拷贝

    public Object clone() {Object clone = null;try {clone = super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return clone;}

测试代码:

// ClassA 实现了 Cloneable 接口
ClassA a = new ClassA();
a.setXXX();ClassA b = (ClassA) c.clone();
b.setXXX();

以上方法不过多赘述


这篇文章主要通过调用对象,实现浅拷贝和深拷贝。

看完图说理论:

浅Copy是指被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都指向原来的对象。简单点说就是,只复制了引用,而没有复制真正的对象内容。

深Copy是指被复制的对象的所有变量都含有与原来对象相同的值,属性中的对象都指向被复制过的新对象中属性,而不再是原型对象中的属性。简单点说,就是深Copy把所有的对象的引用以及对象都复制了一遍,在堆中是存在两个相互独立的对象,以及属性中的对象也是相互独立的。


说完了浅拷贝深拷贝,正式开始编码,还是拿游戏地图举例子

非常重要:大家着重看clone()方法

首先实现浅拷贝(Shallow Copy):

总地图GameMap代码:

public class ShallowCopyGameMap {private String tree;private String mountain;public String getTree() {return tree;}public void setTree(String tree) {this.tree = tree;}public String getMountain() {return mountain;}public void setMountain(String mountain) {this.mountain = mountain;}public Object clone() {Object o = null;try {o = super.clone();} catch (CloneNotSupportedException e) {System.out.println(e.toString());}return o;}@Overridepublic String toString() {return "{" +"tree='" + tree + '\'' +", mountain='" + mountain + '\'' +'}';}
}

LOL游戏地图LOLGameMap如下:

/*** @description:* 浅拷贝*/
public class ShallowCopyLOLGameMap implements Cloneable {private String dragon;private ShallowCopyGameMap gameMap; // 关联GameMap对象public ShallowCopyLOLGameMap(String dragon, ShallowCopyGameMap gameMap) {this.dragon = dragon;this.gameMap = gameMap;}public String getDragon() {return dragon;}public void setDragon(String dragon) {this.dragon = dragon;}public ShallowCopyGameMap getGameMap() {return gameMap;}public void setGameMap(String tree, String mountain) {gameMap.setTree(tree);gameMap.setMountain(mountain);}public Object clone() {Object clone = null;try {clone = super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return clone;}@Overridepublic String toString() {return "{" +"dragon='" + dragon + '\'' +", gameMap=" + gameMap +'}';}
}

这两个类基本相似,都实现了Cloneable接口

接下来进行测试:

public static void main(String[] args) {System.out.println("浅拷贝测试");ShallowCopyGameMap gameMap = new ShallowCopyGameMap();ShallowCopyLOLGameMap lolGameMap1 = new ShallowCopyLOLGameMap("纳什男爵", gameMap);lolGameMap1.setGameMap("树","山");System.out.println("地图1:" + lolGameMap1);ShallowCopyLOLGameMap lolGameMap2 = (ShallowCopyLOLGameMap) lolGameMap1.clone();lolGameMap2.setGameMap("树2", "山2");System.out.println("地图2:" + lolGameMap2);ShallowCopyLOLGameMap lolGameMap3 = (ShallowCopyLOLGameMap) lolGameMap2.clone();lolGameMap3.setGameMap("树3", "山3");System.out.println("地图3:" + lolGameMap3);System.out.println("重新查看前两个地图: ");System.out.println("地图1:" + lolGameMap1);System.out.println("地图2:" + lolGameMap2);}

测试结果:

浅拷贝测试
地图1:{dragon='纳什男爵', gameMap={tree='树', mountain='山'}}
地图2:{dragon='纳什男爵', gameMap={tree='树2', mountain='山2'}}
地图3:{dragon='纳什男爵', gameMap={tree='树3', mountain='山3'}}
重新查看前两个地图:
地图1:{dragon='纳什男爵', gameMap={tree='树3', mountain='山3'}}
地图2:{dragon='纳什男爵', gameMap={tree='树3', mountain='山3'}}

这就是浅拷贝的测试结果,实际开发中要非常留意这个问题,最好在测试时将之前的对象再进行测试输出一次


我这里提供两种方式实现深拷贝:串行化非串行化

非串行化方式实现:(还是通过实现Cloneable接口,注意这里的clone()方法与浅拷贝的区别)

深拷贝(非串行化):总地图GameMap代码:代码与浅拷贝相同,不过多解释

public class DeepCopyGameMap2 implements Cloneable {private String tree;private String mountain;public String getTree() {return tree;}public void setTree(String tree) {this.tree = tree;}public String getMountain() {return mountain;}public void setMountain(String mountain) {this.mountain = mountain;}public Object clone() {Object o = null;try {o = super.clone();} catch (CloneNotSupportedException e) {System.out.println(e.toString());}return o;}@Overridepublic String toString() {return "{" +"tree='" + tree + '\'' +", mountain='" + mountain + '\'' +'}';}
}

深拷贝(非串行化):LOL游戏地图LOLGameMap如下:

特别注意:注意这里的clone()方法与浅拷贝的区别:

/*** @description:* 通过转换为二进制进行深拷贝*/
public class DeepCopyLOLGameMap2 implements Cloneable {private String dragon;private DeepCopyGameMap2 deepCopyGameMap;public DeepCopyLOLGameMap2(String dragon, DeepCopyGameMap2 deepCopyGameMap) {this.dragon = dragon;this.deepCopyGameMap = deepCopyGameMap;}public String getDragon() {return dragon;}public void setDragon(String dragon) {this.dragon = dragon;}public DeepCopyGameMap2 getGameMap() {return deepCopyGameMap;}public void setDeepCopyGameMap2(String tree, String mountain) {deepCopyGameMap.setTree(tree);deepCopyGameMap.setMountain(mountain);}// 非串行化方式, 在LOLGameMap的clone()方法中调用总地图的clone()方法public DeepCopyLOLGameMap2 clone() {DeepCopyLOLGameMap2 clone = null;try {clone = (DeepCopyLOLGameMap2)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}assert clone != null; // 非空判断,可以忽略// 深浅拷贝的区别在这里!!!!!  // 使用了GameMap总地图的clone()方法// GameMap的字段也是浅拷贝中出错变化的地方clone.deepCopyGameMap = (DeepCopyGameMap2) deepCopyGameMap.clone();return clone;}@Overridepublic String toString() {return "{" +"dragon='" + dragon + '\'' +", deepCopyGameMap=" + deepCopyGameMap +'}';}
}

深拷贝(非串行化)测试代码:

public static void main(String[] args) {System.out.println("深拷贝测试----  非串行化方式");DeepCopyGameMap2 deepCopyGameMap = new DeepCopyGameMap2();deepCopyGameMap.setTree("树");deepCopyGameMap.setMountain("山");DeepCopyLOLGameMap2 lolGameMap1 = new DeepCopyLOLGameMap2("纳什男爵",deepCopyGameMap);lolGameMap1.setDeepCopyGameMap2("树","山");System.out.println("地图1:" + lolGameMap1);DeepCopyLOLGameMap2 lolGameMap2 = (DeepCopyLOLGameMap2) lolGameMap1.clone();lolGameMap2.setDeepCopyGameMap2("树2", "山2");System.out.println("地图2:" + lolGameMap2);DeepCopyLOLGameMap2 lolGameMap3 = (DeepCopyLOLGameMap2) lolGameMap2.clone();lolGameMap3.setDeepCopyGameMap2("树3", "山3");System.out.println("地图3:" + lolGameMap3);System.out.println("重新查看前两个地图: ");System.out.println("地图1:" + lolGameMap1);System.out.println("地图2:" + lolGameMap2);}
}

测试结果如下:

深拷贝测试----  非串行化方式
地图1:{dragon='纳什男爵', deepCopyGameMap={tree='树', mountain='山'}}
地图2:{dragon='纳什男爵', deepCopyGameMap={tree='树2', mountain='山2'}}
地图3:{dragon='纳什男爵', deepCopyGameMap={tree='树3', mountain='山3'}}
重新查看前两个地图:
地图1:{dragon='纳什男爵', deepCopyGameMap={tree='树', mountain='山'}}
地图2:{dragon='纳什男爵', deepCopyGameMap={tree='树2', mountain='山2'}}

串行化方式实现:(必须实现Serializable)

深拷贝(串行化):总地图GameMap代码:

public class DeepCopyGameMap implements Serializable {private String tree;private String mountain;public String getTree() {return tree;}public void setTree(String tree) {this.tree = tree;}public String getMountain() {return mountain;}public void setMountain(String mountain) {this.mountain = mountain;}public Object clone() {Object o = null;try {o = super.clone();} catch (CloneNotSupportedException e) {System.out.println(e.toString());}return o;}@Overridepublic String toString() {return "{" +"tree='" + tree + '\'' +", mountain='" + mountain + '\'' +'}';}
}

深拷贝(串行化):LOL游戏地图LOLGameMap如下:

/*** @description:* 通过串行化方式进行深拷贝*/
public class DeepCopyLOLGameMap implements Serializable {private String dragon;private DeepCopyGameMap deepCopyGameMap;public DeepCopyLOLGameMap(String dragon, DeepCopyGameMap deepCopyGameMap) {this.dragon = dragon;this.deepCopyGameMap = deepCopyGameMap;}public String getDragon() {return dragon;}public void setDragon(String dragon) {this.dragon = dragon;}public DeepCopyGameMap getDeepCopyGameMap() {return deepCopyGameMap;}public void setDeepCopyGameMap(String tree, String mountain) {deepCopyGameMap.setTree(tree);deepCopyGameMap.setMountain(mountain);}// 串行化方式进行深拷贝public DeepCopyLOLGameMap clone() {DeepCopyLOLGameMap clone = null;try {//写入当前对象的二进制流ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(this);//读出二进制流产生新的对象ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);clone = (DeepCopyLOLGameMap)ois.readObject();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return clone;}@Overridepublic String toString() {return "{" +"dragon='" + dragon + '\'' +", deepCopyGameMap=" + deepCopyGameMap +'}';}
}

深拷贝(串行化)测试代码:

    public static void main(String[] args) throws CloneNotSupportedException {System.out.println("深拷贝测试--- 串行化方式");DeepCopyGameMap deepCopyGameMap = new DeepCopyGameMap();DeepCopyLOLGameMap lolGameMap1 = new DeepCopyLOLGameMap("纳什男爵", deepCopyGameMap);lolGameMap1.setDeepCopyGameMap("树","山");System.out.println("地图1:" + lolGameMap1);DeepCopyLOLGameMap lolGameMap2 = (DeepCopyLOLGameMap) lolGameMap1.clone();lolGameMap2.setDeepCopyGameMap("树2", "山2");System.out.println("地图2:" + lolGameMap2);DeepCopyLOLGameMap lolGameMap3 = (DeepCopyLOLGameMap) lolGameMap2.clone();lolGameMap3.setDeepCopyGameMap("树3", "山3");System.out.println("地图3:" + lolGameMap3);System.out.println("重新查看前两个地图: ");System.out.println("地图1:" + lolGameMap1);System.out.println("地图2:" + lolGameMap2);}

测试结果如下:

深拷贝测试--- 串行化方式
地图1:{dragon='纳什男爵', deepCopyGameMap={tree='树', mountain='山'}}
地图2:{dragon='纳什男爵', deepCopyGameMap={tree='树2', mountain='山2'}}
地图3:{dragon='纳什男爵', deepCopyGameMap={tree='树3', mountain='山3'}}
重新查看前两个地图:
地图1:{dragon='纳什男爵', deepCopyGameMap={tree='树', mountain='山'}}
地图2:{dragon='纳什男爵', deepCopyGameMap={tree='树2', mountain='山2'}}

注意LOLGameMapclone()方法


总结一下:

原型模式通过Object的clone()方法实现,由于是内存操作,无视构造方法和访问权限,直接获取新的对象。但对于引用类型,需使用深拷贝,其它浅拷贝即可。


代码已经上传到Git:请点击访问

如果大家对于原型模式还有更多的使用技巧和使用心得,欢迎评论并在评论中分享自己的链接!

GOF(五)-原型模式【推荐】相关推荐

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

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

  2. 设计模式(创建型)之原型模式

    GOF 给原型模式 的定义为:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 在 C++和Java 中都提供了clone()方法来实现对象的克隆,但是在Java中必须要实现Clone ...

  3. 设计模式笔记五:原型模式

    原文:http://www.runoob.com/design-pattern/ 少许个人理解,如有错误请指出 菜鸟教程讲的比较难懂,有篇简洁易懂的博客: http://blog.csdn.net/j ...

  4. 设计模式(五)—— 原型模式(定义、案例分析、特点、缺点)

    文章目录 前言 正文 一.定义 二.模式结构及分析 (一) 模式结构 (二) 模式分析 三.情景假设 四.情景分析 (一) 浅克隆 (二) 深克隆 五.模式优点.缺点 (一)模式优点 (二)模式缺点 ...

  5. 设计模式快速学习(五)原型模式

    用于创建重复的对象,同时又能保证性能.通俗的讲,原型模式就是克隆对象,直接copy字节码,不走构造方法,性能非常高.ORM中经常用到. 注意 只支持9种数据类型的深拷贝: 8大基本类型(int lon ...

  6. 五、原型模式(Prototype Pattern)

    1. 什么是原型模式(Prototype Pattern) 在需要创建大量相同或者相似的对象时,先创建一个原型对象,然后利用这个原型对象进行克隆,从而得到大量对象 java中可以利用Object中的c ...

  7. 设计模式五:原型模式

    目录 原型模式 浅克隆 深克隆 原型模式 原型模式是指:原型实例指定原型对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式的适用场景: 1.类初始化消耗资源较多 2.new产生一个对象需要非常繁 ...

  8. 看图记设计模式【五】,创建模式系列:原型模式

    原型模式 亦称: 克隆.Clone.Prototype 意图 原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类. 一图说明: 还是老话,请在阅读本篇文章后,记住此 ...

  9. 初学 Java 设计模式(五):实战原型模式 「英雄联盟齐天大圣-真假猴王」

    一.原型模式介绍 1. 解决的问题 主要解决的问题就是创建重复对象,这部分对象内容本身比较复杂,生成过程可能从库中或者RPC接口中获取数据的耗时较长,因此采用克隆的方式节省时间. 2. 定义 原型模式 ...

最新文章

  1. Microsoft Speech SDK 编程入门
  2. ASP.NET dropdownlist绑定数据却显示System.Data.DataRowView
  3. IDEA打包成可执行的JAR包
  4. 21-Heartbeat配置文件authkey重要参数讲解
  5. 计算机基础- -认识汇编
  6. 【转】消息队列应用场景
  7. Unix domain socket 简介(进程间通信,进程通信)
  8. element icon图标方向旋转
  9. labVIEW学习笔记(二)公式节点、数组
  10. pg日期转周_postgres日期格式转换
  11. equals()与hashCode()方法协作约定
  12. msys2下用cmake构建poppler和libpng
  13. 产品经理必须要掌握的数据分析能力
  14. PointRCNN 车辆 行人 自行车识别
  15. 苹果微信cookie传不到服务器,cookie解决微信不能存储localStorage的问题
  16. GX Works3 设置 TCP + SLMP 与三菱FX5U通信
  17. 记录一下nginx代理引起的ip失真问题
  18. 利用Python实现股票可视做T盈亏
  19. 叶史瓦大学计算机专业,叶史瓦的大学排名
  20. telnet “出现正在连接” “对主机遗失问题” 完美解决

热门文章

  1. 小眼睛适合大框还是小框眼镜_【图】小眼睛适合什么眼镜框呢 你选对了吗_小眼睛_伊秀美容网|yxlady.com...
  2. collecting package metadata慢_手游版LOL更新慢怎么解决 英雄联盟手游更新慢解决方法_英雄联盟手游...
  3. 华为P30价格曝光,加入超级光谱镜头 有望登顶DxOMark
  4. aspnet+mvc三层架构汽车4S店机动车辆年检和保养维修管理系统C#
  5. 重点人员动态管控系统开发,智慧公安合成作战平台搭建
  6. 【游戏设计图形学】在地图上生成蜿蜒河流的两种方法
  7. TPA2080D1相关介绍
  8. MATLAB信号处理——信号的变换(5)
  9. 如何把友谊小船升华为爱情巨轮?
  10. 1970年至今(2007/7/20)原油价格走势图