软件设计模式——原型模式
摘要
主要介绍原型设计模式的原理,原型设计模式就是java中深拷贝和浅拷贝思想的原理。
一、新对象创建问题
现在有一只羊,姓名为 Tom,年龄为 1,颜色为白色,请编写程序创建和 Tom 羊属性完全相同的 10 只羊。
package com.zhuangxiaoyan.designpattern.clonemodel;/*** @Classname CloneModel* @Description1)优点是比较好理解,简单易操作2)在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低3)总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活* @Date 2022/3/27 9:16* @Created by xjl*/
public class CloneModel {public static void main(String[] args) {for (int i = 0; i < 10; i++) {Sheep sheep = new Sheep("Tom", 1,"白色");System.out.println(sheep);}}
}/*** @description 原型类* @param: null* @date: 2022/3/27 9:17* @return:* @author: xjl
*/
class Sheep {private String name;private Integer age;private String color;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public Sheep(String name, Integer age, String color) {this.name = name;this.age = age;this.color = color;}
}
传统方法优缺点
- 1)优点是比较好理解,简单易操作
- 2)在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低
- 3)总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活
改进的思路分析
Java 中 Object 类是所有类的根类,Object 类提供了一个 clone 方法,该方法可以将一个 Java 对象复制一份,但是需要实现 clone 的 Java 类必须要实现一个接口 Cloneable,该接口表示该类能够复制且具有复制的能力 ==> 原型模式。
二、原型模式(Prototype 模式)
1)原型模式(Prototype 模式)是指:用原型实例指定创建对象种类,并通过拷贝原型创建新的对象。
2)原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。
3)工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即
对象.clone()。
4)形象的理解:孙大圣拔出猴毛,变出其它孙大圣
原理结构图说明
- 1)
Prototype
:原型类,声明一个克隆自己的接口 - 2)
ConcretePrototype
:具体的原型类,实现一个克隆自己的操作 - 3)
Client
:让一个原型对象克隆自己,创建一个新的对象(属性相同)
使用原型模式改进传统方式式,让程序具有更高的效率和扩展性
三、JDK 源码分析
Spring 框架中,创建ApplicationContext
时,使用的getBean
方法中使用到了原型模式
四、浅拷贝和深拷贝原理
4.1 浅拷贝基本介绍
- 1)对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象
- 2)对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
- 3)前面我们克隆羊就是浅拷贝
- 4)浅拷贝是使用默认的 clone 方法来实现:
sheep=(Sheep)super.clone();
4.2 深拷贝基本介绍
- 1)复制对象的所有基本数据类型的成员变量值
- 2)为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝
- 3)深拷贝实现方式 1:重写 clone 方法来实现深拷贝
- 4)深拷贝实现方式 2:通过对象序列化实现深拷贝
package com.zhuangxiaoyan.designpattern.clonemodel;import org.junit.Test;
import java.io.*;class DeepClonableTarget implements Serializable, Cloneable {private String cloneName;private String cloneClass;public DeepClonableTarget(String cloneName, String cloneClass) {this.cloneName = cloneName;this.cloneClass = cloneClass;}public String getCloneName() {return cloneName;}public void setCloneName(String cloneName) {this.cloneName = cloneName;}public String getCloneClass() {return cloneClass;}public void setCloneClass(String cloneClass) {this.cloneClass = cloneClass;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}/*** @description 重写 clone 方法来实现深拷贝* @param: null* @date: 2022/3/27 9:48* @return:* @author: xjl
*/
class DeepPrototype implements Serializable, Cloneable {private String name;private DeepClonableTarget deepClonableTarget;public DeepPrototype() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public DeepClonableTarget getDeepClonableTarget() {return deepClonableTarget;}public void setDeepClonableTarget(DeepClonableTarget deepClonableTarget) {this.deepClonableTarget = deepClonableTarget;}@Overrideprotected Object clone() throws CloneNotSupportedException {//基本数据类型拷贝Object object = super.clone();//引用类型拷贝DeepPrototype deepPrototype = (DeepPrototype) object;deepPrototype.deepClonableTarget = (DeepClonableTarget) deepClonableTarget.clone();return object;}
}/*** @description 深拷贝方式 通过对象序列化实现深拷贝* @param: null* @date: 2022/3/27 9:41* @return:* @author: xjl*/
class DeepPrototypeV2 implements Serializable, Cloneable {private String name;private DeepClonableTarget deepClonableTarget;public DeepPrototypeV2() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public DeepClonableTarget getDeepClonableTarget() {return deepClonableTarget;}public void setDeepClonableTarget(DeepClonableTarget deepClonableTarget) {this.deepClonableTarget = deepClonableTarget;}/*** @description 通过对象序列化实现深拷贝* @param:* @date: 2022/3/27 9:55* @return: com.zhuangxiaoyan.designpattern.clonemodel.DeepPrototype* @author: xjl*/public DeepPrototypeV2 deepClone() {ByteArrayOutputStream bos = null;ObjectOutputStream oos = null;ByteArrayInputStream bis = null;ObjectInputStream ois = null;try {// 序列化bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);oos.writeObject(this);// 反序列化bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);return (DeepPrototypeV2) ois.readObject();} catch (Exception e) {e.printStackTrace();return null;} finally {try {if (ois != null) {ois.close();}if (bis != null) {bis.close();}if (oos != null) {oos.close();}if (bos != null) {bos.close();}} catch (IOException e) {e.printStackTrace();}}}
}/*** @Classname DeepTestDemo* @Description* @Date 2022/3/27 9:38* @Created by xjl*/
public class DeepTestDemo {@Testpublic void testv1() throws CloneNotSupportedException {DeepPrototype prototype = new DeepPrototype();prototype.setName("庄小焱");prototype.setDeepClonableTarget(new DeepClonableTarget("及时雨", "及时雨的类"));DeepPrototype clone1 = (DeepPrototype) prototype.clone();DeepPrototype clone2 = (DeepPrototype) prototype.clone();DeepPrototype clone3 = (DeepPrototype) prototype.clone();DeepPrototype clone4 = (DeepPrototype) prototype.clone();DeepPrototype clone5 = (DeepPrototype) prototype.clone();System.out.println(prototype.getName() + ", " + prototype.getDeepClonableTarget().hashCode()); // 庄小焱, 1554874502System.out.println(clone1.getName() + ", " + clone1.getDeepClonableTarget().hashCode()); // 庄小焱, 1846274136System.out.println(clone2.getName() + ", " + clone2.getDeepClonableTarget().hashCode()); // 庄小焱, 1639705018System.out.println(clone3.getName() + ", " + clone3.getDeepClonableTarget().hashCode()); // 庄小焱, 1627674070System.out.println(clone4.getName() + ", " + clone4.getDeepClonableTarget().hashCode()); // 庄小焱, 1360875712System.out.println(clone5.getName() + ", " + clone5.getDeepClonableTarget().hashCode()); // 庄小焱, 1625635731}@Testpublic void testv2() throws CloneNotSupportedException {DeepPrototypeV2 prototypev2 = new DeepPrototypeV2();prototypev2.setName("庄小焱");prototypev2.setDeepClonableTarget(new DeepClonableTarget("zhuangxiaoyan", "yatou"));DeepPrototypeV2 clone1 = prototypev2.deepClone();DeepPrototypeV2 clone2 = prototypev2.deepClone();DeepPrototypeV2 clone3 = prototypev2.deepClone();DeepPrototypeV2 clone4 = prototypev2.deepClone();DeepPrototypeV2 clone5 = prototypev2.deepClone();System.out.println(prototypev2.getName() + ", " + prototypev2.getDeepClonableTarget().hashCode()); // 庄小焱,644117698System.out.println(clone1.getName() + ", " + clone1.getDeepClonableTarget().hashCode()); // 庄小焱, 317574433System.out.println(clone2.getName() + ", " + clone2.getDeepClonableTarget().hashCode()); // 庄小焱, 885284298System.out.println(clone3.getName() + ", " + clone3.getDeepClonableTarget().hashCode()); // 庄小焱, 1389133897System.out.println(clone4.getName() + ", " + clone4.getDeepClonableTarget().hashCode()); // 庄小焱, 1534030866System.out.println(clone5.getName() + ", " + clone5.getDeepClonableTarget().hashCode()); // 庄小焱, 664223387}
}
方式 1 和方式 2 对比
- 在对象引用类型的成员属性较少时,方式 1 简单;在对象引用类型的成员属性较多时,方式 2 简单
- 在对象引用类型的成员属性经常发生变化时,方式 1 需要同步修改,方式 2 不用修改
- 推荐使用方式 2:耦合性低、可维护性强、扩展性高
注意事项和细节
- 1)优点:创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
- 2)优点:不用重新初始化对象,而是动态地获得对象运行时的状态
- 3)优点:如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
- 4)缺点:在实现深克隆的时候可能需要比较复杂的代码
- 5)缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了OCP 原则,这点请同学们注意。
博文参考
软件设计模式——原型模式相关推荐
- 软件设计模式—命令模式
前篇--软件设计模式-基础 前篇--软件设计模式-三种工厂模式 前篇--软件设计模式-装饰者模式 前篇--软件设计模式-单例模式 前篇--软件设计模式-原型模式 命令模式是对象行为型模式 目录 1. ...
- 设计模式 原型模式_创新设计模式:原型模式
设计模式 原型模式 原型模式用于创建对象的副本. 这种模式非常有用,特别是当从头开始创建对象的成本很高时. 与builder , factory和abstract factory模式相比,它不会从头开 ...
- 设计模式 原型模式_设计模式:原型
设计模式 原型模式 创新设计模式之一是原型设计模式 . 尽管原型是创造模式,但它在概念上与其他模式有所区别. 我的意思是原型在某种意义上创造了自己. 我将在下面解释. 原型模式的所有魔力都基于Java ...
- 设计模式 原型模式_原型设计模式:创建另一个小车
设计模式 原型模式 创建对象确实是一个耗时的过程,也是一件昂贵的事情. 因此,我们现在正冒险节省时间和金钱. 我们该怎么做? 克隆奇迹多莉 有人记得多莉吗? 是的,是绵羊,是第一个被克隆的哺乳动物. ...
- Java常用设计模式————原型模式(一)
介绍 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. 原型模式用于创建重复的对象,同时又能保证性能.当直接创建对象的代价比较大时,则采用 ...
- 第六章 Caché 设计模式 原型模式
文章目录 第六章 Caché 设计模式 原型模式 定义 使用场景 优点 结构图 描述 示例 初级写法 缺点 中级写法 缺点 高级写法 (浅复制) 浅复制 深复制 完整示例 简历类(复制类) 对象类(工 ...
- C++设计模式——原型模式(Prototype Pattern)
C++设计模式--原型模式(Prototype Pattern) 微信公众号:幼儿园的学霸 目录 文章目录 C++设计模式--原型模式(Prototype Pattern) 目录 定义 代码示例 普通 ...
- c++设计模式--原型模式(proto pattern)
一.原理讲解 原型模式其实就是对类对象某个时刻的状态进行备份或者拷贝下来.比如该类的对象进行一系列赋值操作,然后需要保存某个瞬时状态,则用原型模式克隆下来.其中类对象某个瞬时状态用this表示,通过t ...
- 设计模式---原型模式(Prototype Pattern)
在编程中有时候我们会发现,当我们需要一个实例,可是这个实例的创建过程十分复杂,在执行过程中 会消耗大量的时间,同时创建第一个实例和创建第二个时间的初始化信息并未改变.在此种情况下,直接New 一个实例 ...
最新文章
- java之==和equals区别
- java 基本类型之间的转换
- FreeOTP可以用作谷歌认证的替代
- 新型机器学习算法:正则化理解
- 网络流24题之餐巾计划问题
- 利用 Angular Directive 和 @HostBinding 实现输入文本框随着键盘输入自动变色效果
- 解决配置Ubuntu中vnc远程显示灰屏
- 权限列表(包字典)递归成树状结构
- 评分组件(RatingBar)
- org.neo4j.kernel.StoreLockException: Store and its lock file has been locked by another process
- SSD 下的 MySQL IO 优化
- 计算机c盘容易满怎么办,C盘快满了怎么办 如何清理C盘垃圾?
- 如果你毕业想进央企, 那就选这些大学, 性价比很高
- 一条SQL语句在MySQL中执行过程全解析
- 发送邮件被对方服务器退回_国内邮件群发
- MATLAB算法实战应用案例精讲-【智能优化算法】黑寡妇算法-BWO(附matlab代码)
- IOl数据流中的字节流
- 华为harmonyos手机开发者,华为鸿蒙HarmonyOS2.0手机开发者Beta版正式发布
- app logo显示不全没有铺满
- 谷歌浏览器控制台如何切换中英文
热门文章
- Citrix 服务器虚拟化之二十四 桌面虚拟化之Remote PC Access
- JAVA 计算当月有多少天
- 5G基站用电难题的转机?8大突破案例、25项政策支持!
- 一句话木马SQL注入
- [SQL]对取出来的数据构造实验组和对照组的方法
- 2006-5-7 18:42:00 崔永元逗老外逗出的震撼!!!!绝对经典
- 谷歌浏览器插件——Ajax Interceptor,一个用于修改 ajax 请求响应的 chrome 扩展,可以修改ajax请求返回结果,在浏览器上直接mock数据
- cpuidle framework in Linux Kernel(2)what's idle state
- easyui 根据值查找匹配
- php高级教程blog博,贾沦一盒纤斯人博客|PHP高级教程|C |J