设计模式五-----原型模式

设计模式五-----原型模式

​ 原型模式的构造过程就是选择一个对象(被称为原型对象或者“样本”),通过调用它的“克隆”方法就获得和它一样的对象。一般,我们称这个克隆出的结果为“副本”。

TIPs:	在CLR底层,克隆本身又是一个ByDesign的内置机制。
	CLR:公共语言运行库 (common language runtime,CLR) 是托管代码执行核心中的引擎。运行库为托管代码提供各种服务,如跨语言集成、代码访问安全性、对象生存期管理、调试和分析支持。它是整个.NET框架的核心,它为.NET应用程序提供了一个托管的代码执行环境。它实际上是驻留在内存里的一段代理代码,负责应用程序在整个执行期间的代码管理工作。
	ByDesign:SAP第一个完全基于以服务导向架构平台(SOA)设计并开发的企业资源管理解决方案,其工作中心覆盖从前台到后台的各项应用,全面支持中型企业可能涉及的所有业务需求。	

​ 如果对象类型变化的相对频繁,“没完没了”地为它们创建各种工厂是不值得的。另外,有时我们需要构造的不是只有初始状态的类型实例,而是需要构造与某个对象“当时”状态一样的实例。在这种情况下,前几个创建型模式就无能为力。因此,类似于我们在单件模式中吧対实例数量的控制放在Singleton内部一样,这里也把new()的工作放到每个具体类型内部。不过区别于前面说的一般性的“构造”,这里称之为“克隆”。

​ 经典原型模式就是采用这个想法:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

​ 一个复杂的对象可以提供Clone()方法克隆整个对象,也可以同时提供ClonePartA()、ClonePartB()等方法克隆出局部对象,甚至可以克隆出相对独立的其他类型。

一、克隆模式适用场景

1、如果需要的类型不是编译状态就已经确定的,而是运行过程中动态选择的,为了不引入其他对象(Factory、Builder)就可以继续创造出新的对象,最简单的方法就是采用“克隆”。

2、如果需要的不是某个“初始状态”的对象,而是“恰巧”某个状态的对象。

3、不希望“没完没了”地创建工厂类型

4、在一些其他语境下,如,类型本身可枚举的实例非常固定。如红绿灯,很多时候该类型只有3个实例,当再次需要构造“红灯”状态时,与其通过某种机制new(),还不如通过一个现成的"红灯"克隆一个出来。

​ 经典原型模式静态图,如下

在这里插入图片描述

​ IPrototype定义了符合原型模式要求的类型特性(Clone方法/ClonePartA/ClonePartB)。客户程序依赖的仅仅是IPrototype,而且通过Clone()方法获取的也是IPrototype,因此满足”依赖倒置“的要求。

​ 依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

二、克隆的特点

​ 克隆的副本不仅具有与样本一样的类型,而且状态也一致。

​ 样本与副本是两个独立的实例,除非某些状态有意设置为共享或全局,否则在克隆结束时,两者可以相互独立的变化。

三、克隆机制

1.浅表复制

​ MemberwiseClone()方法执行的是浅表复制/浅复制/映像复制。该方法创建一个新的对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型的,则对该字段执行逐位复制;如果字段是引用类型的,则复制引用但不复制引用的对象(也就是仅保存一个指针)。因此,样本及其副本中引用型成员指向的是同一个对象。

​ 复制的过程是可期的,即,一个实例哪些内容可以复制是可预料的,实现上等于将“栈”内的逐位复制到一块新的空间即可,而对于那些“堆”中的内容,就先不列入考虑。

	栈内存:栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。
	堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。

堆和栈的对比分析
 1、堆栈空间分配
  栈(操作系统):由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
  堆(操作系统):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表。
 2、堆栈缓存方式
  栈使用的是一级缓存,他们通常都是被调用时处于存储空间中,调用完毕立即释放。
  堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
 3、堆栈数据结构区别
  堆(数据结构):堆可以被看成是一棵树,如:堆排序。
  栈(数据结构):一种先进后出的数据结构。

2.深层复制

​ 为了满足某些复杂场景的需要。

​ 深层复制针对那些引用类型另外开辟的一块内存,把引用目标地址的内容逐个位地复制一份。

​ 比较难以实现,因为很多情况下对象内部的成员也是引用类型,而且很可能会多层次嵌套下去。

适用场景—看类图/E-R图

​ 1.如果设计的足够详细,那么Association、Dependency、Composition、Aggregatation都需要引起注意,因为他们一般都是引用关系,如果进行深层复制就需要定制。

​ 2.结合数据库的ORM结果,如果E-R关系中存在挖减,那么一般映射为对象也有引用关系,一般深层复制需要定制。

​ 3.基于纯XML数据环境开发。由于XML本身就是层级结构的,所以,当用XML数据来表示具有引用关系的对象时,深层复制反而不需要定制,因为它本身就是一个文本,可以直接用字符串操作。

实现深层复制的方法

​ 1.手工逐层完成。例如,遇到引用类型,就在新对象中重新new()一个,但要确保这个new()出来的实例是一个新的独立实例。

​ 2.序列化。给目标类型贴标签,编译器会沿着引用和继承关系检查,一查到底。对于复制过程复杂的情况就需要自定义序列化的过程了。

​ 自定义方法需要结合实际,有时仅是简单的制作实现克隆的工具类型即可,有时需要使用粗细粒度复制。

四、小结

​ 原型模式是创建型模式中比较强调个体特征的模式,它同样适用于具体类型快速变化的环境,只不过它没有独立出一个工厂类型,而是通过自我复制(克隆)过程实现新实例创建的。

​ 项目中,使用原型模式的关键不在于定义一个IPrototype接口,而在于如何又好又快地完成克隆的过程。

,而是通过自我复制(克隆)过程实现新实例创建的。

​ 项目中,使用原型模式的关键不在于定义一个IPrototype接口,而在于如何又好又快地完成克隆的过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值