设计模式(五)原型模式
1、简介
原型模式使用原型实例指定创建对象的种类,并且通过拷贝原型对象创建新的对象。提供了应该通过已存在对象进行新对象创建的接口clone。原型模式实际上就是从一个对象再创建另外一个可定制的对象,并且不需要知道创建的细节。在初始化的信息不发生变化的情况下,克隆是最好的办法,既隐藏了对象创建的细节,又大大提高了性能。因为如果不用clone,每次new都需要执行一次构造函数,如果构造函数执行时间很长,那么多次的执行初始化操作太低效了。
原型模式实现clone接口的时候必须使用深拷贝。
原型模式的重点在从自身赋值自己创建新的类对象,隐藏创建的细节。
2、类图
3、原型模式角色
(1)抽象原型(Prototype)角色:规定了具体原型对象必须实现的接口(如果要提供深拷贝,则必须具有实现clone的规定);
(2)具体原型(Concrete Prototype):从抽象原型派生而来,是客户程序使用的对象,即被复制的对象,需要实现抽象原型角色所要求的接口;
(3)客户端(Client):使用原型对象的客户端程序。
4、原型模式使用场景
原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是由对象的内部提供克隆的方法,通过clone方法返回一个对象的副本。
如:
- 当一个系统应该独立于它的产品创建、构成和表示时,要使用原型模式;
- 当要实例化的类是在运行时刻指定时,如通过动态装载;
- 为了避免创建一个与产品类层次平行的工厂类层次时;
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆原型可能比每次用合适的状态手工实例化原型类更方便一些。
5、优缺点
优点:
- 原型模式对客户隐藏了具体的产品类;
- 运行时刻增加和删除产品: 原型模式允许只通过客户注册原型实例就可以将一个新的具体产品类并入系统;
- 改变值以指定新对象: 高度动态的系统允许通过对象复合定义新的行为。如通过为一个对象变量指定值并且不定义新的类。通过实例化已有类并且将实例注册为客户对象的原型,就可以有效定义新类别的对象。客户可以将职责代理给原型,从而表现出新的行为;
- 改变结构以指定新对象:许多应用由部件和子部件来创建对象;
- 减少子类的构造,Prototype模式克隆一个原型而不是请求一个工厂方法去产生一个新的对象;
- 用类动态配置应用 一些运行时刻环境允许动态将类装载到应用中;
- 使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显;
- 使用原型模式的另一个好处是简化对象的创建,使得创建对象很简单。
缺点:
原型模式的主要缺陷是每一个抽象原型Prototype的子类都必须实现clone操作,实现clone函数可能会很困难。当所考虑的类已经存在时就难以新增clone操作,当内部包括一些不支持拷贝或有循环引用的对象时,实现克隆可能也会很困难的。
6、浅拷贝与深拷贝
(1)浅拷贝
被拷贝对象的所有变量都含有与原对象相同的值,而且对其他对象的引用仍然是指向原来的对象。即浅拷贝只负责当前对象实例,对引用的对象不做拷贝。
(2)深拷贝
被拷贝对象的所有的变量都含有与原来对象相同的值,除了引用其他对象的变量。引用其他对象的变量将指向一个被拷贝的新对象,而不再是原有被引用对象。即深拷贝把要拷贝的对象所引用的对象也都拷贝了一次。
深拷贝要深入到多少层,是一个不确定的问题。在决定以深拷贝的方式拷贝一个对象的时候,必须决定对间接拷贝的对象是采取浅拷贝还是深拷贝还是继续采用深拷贝。因此,在采取深拷贝时,需要决定多深才算深。此外,在深拷贝的过程中,很可能会出现循环引用的问题。
7、代码实例
(1)浅拷贝
1 /** 2 * @author it-小林 3 * @desc 4 * @date 2021年07月14日 20:08 5 * 步骤 6 * 1、实现一个接口 Cloneable 7 * 2、重写一个方法 clone() 8 */ 9 public class Video implements Cloneable { 10 11 private String name; 12 13 private Date createTime; 14 15 16 @Override 17 protected Object clone() throws CloneNotSupportedException { 18 return super.clone(); 19 } 20 21 public Video() { 22 } 23 24 public Video(String name, Date createTime) { 25 this.name = name; 26 this.createTime = createTime; 27 } 28 29 public String getName() { 30 return name; 31 } 32 33 public void setName(String name) { 34 this.name = name; 35 } 36 37 public Date getCreateTime() { 38 return createTime; 39 } 40 41 public void setCreateTime(Date createTime) { 42 this.createTime = createTime; 43 } 44 45 @Override 46 public String toString() { 47 return "Video{" + 48 "name='" + name + '\'' + 49 ", createTime=" + createTime + 50 '}'; 51 } 52 }
1 /** 2 * @author it-小林 3 * @desc 4 * @date 2021年07月14日 20:16 5 */ 6 public class BCopy { 7 8 public static void main(String[] args) throws CloneNotSupportedException { 9 //原型对象v1 10 Date date = new Date(); 11 Video v1 = new Video("原型模式", date); 12 Video v2 = (Video) v1.clone(); 13 System.out.println("v1=>" + v1); 14 System.out.println("v2=>" + v2); 15 16 System.out.println("======================"); 17 date.setTime(2114422); 18 System.out.println("v1=>" + v1); 19 System.out.println("v2=>" + v2); 20 21 22 //v1 克隆v2 23 //Video v2 = new Video("原型模式", date); 24 /*Video v2 = (Video) v1.clone(); 25 System.out.println("v2=>" + v2); 26 System.out.println("v2=>hash:" + v2.hashCode()); 27 v2.setName("原型模式复制"); 28 System.out.println(v2);*/ 29 } 30 }
运行结果:
(2)深拷贝
1 /** 2 * @author it-小林 3 * @desc 4 * @date 2021年07月14日 20:08 5 * 步骤 6 * 1、实现一个接口 Cloneable 7 * 2、重写一个方法 clone() 8 */ 9 public class Video implements Cloneable { 10 11 private String name; 12 13 private Date createTime; 14 15 16 @Override 17 protected Object clone() throws CloneNotSupportedException { 18 Object obj = super.clone(); 19 20 Video v = (Video) obj; 21 v.createTime = (Date) this.createTime.clone(); 22 23 return v; 24 } 25 26 public Video() { 27 } 28 29 public Video(String name, Date createTime) { 30 this.name = name; 31 this.createTime = createTime; 32 } 33 34 public String getName() { 35 return name; 36 } 37 38 public void setName(String name) { 39 this.name = name; 40 } 41 42 public Date getCreateTime() { 43 return createTime; 44 } 45 46 public void setCreateTime(Date createTime) { 47 this.createTime = createTime; 48 } 49 50 @Override 51 public String toString() { 52 return "Video{" + 53 "name='" + name + '\'' + 54 ", createTime=" + createTime + 55 '}'; 56 } 57 }
1 /** 2 * @author it-小林 3 * @desc 4 * @date 2021年07月14日 20:16 5 * Spring Bean : 单例模式 原型模式 6 * 原型模式 + 工厂模式 ==》new + 工厂模式 7 * 8 * 9 */ 10 public class BCopy { 11 12 public static void main(String[] args) throws CloneNotSupportedException { 13 //原型对象v1 14 Date date = new Date(); 15 Video v1 = new Video("原型模式", date); 16 Video v2 = (Video) v1.clone(); 17 System.out.println("v1=>" + v1); 18 System.out.println("v2=>" + v2); 19 20 System.out.println("======================"); 21 date.setTime(2114422); 22 System.out.println("v1=>" + v1); 23 System.out.println("v2=>" + v2); 24 25 } 26 }
运行结果:
本文来自博客园,作者:it-小林,转载请注明原文链接:https://www.cnblogs.com/linruitao/p/15012715.html
原文地址:https://www.cnblogs.com/linruitao/p/15012715.html
- =.=
- JavaScript经典面试题之for循环click
- 学习docker on windows (1): 为什么要使用docker
- 使用VS Code开发asp.net core (下)
- 使用VS Code开发asp.net core (上)
- 小程序开发总结
- Silverlight Load Client Image 加载客户端图片
- 使用xUnit为.net core程序进行单元测试(4)
- 使用xUnit为.net core程序进行单元测试(3)
- 使用xUnit为.net core程序进行单元测试(2)
- 使用xUnit为.net core程序进行单元测试(1)
- 用 Identity Server 4 (JWKS 端点和 RS256 算法) 来保护 Python web api
- asp.net core 2.0 查缺补漏
- SQL Server 性能优化之——T-SQL NOT IN 和 NOT Exists
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 看得懂的外观设计模式 python3 实现
- 看得懂的设计模式 享元模式python3 最基本(简单)实现
- python3 最简单的实现 模版设计模式
- Qt 第二步 槽与信号(一) 实现点击按钮并弹窗
- python3 爬虫第一步 简单获取网页基本信息
- python3 爬虫第二步Selenium 使用简单的方式抓取复杂的页面信息
- Qt 第二步 熟悉文件结构组成(二)
- php基础教程 第一步 环境配置及helloworld
- 推荐两个Docker配置检查与启动异常修复方法脚本
- 持续集成gitlab-ci.yml配置文档基础
- php基础教程 第二步 通俗易懂的学习变量、常量与数据类型
- git | Windows下如何利用Linux的命令
- python3 爬虫第三步 本文包你学会正则 不会就来锤我
- php基础教程 第三步 学习字符串及相关函数
- php基础教程 第四步 学习运算符