5.原型模式(Prototype Pattern)
前面的几种模式中,我们使用了不同的构造方法(各种Factory或者Builder)去代替或者说掩盖Java语言之中“new”这个操作来创建对象实例。Java中要创建一个新的对象并不一定只能靠“new”这个关键字的,我们还有“clone()”。
在接触原型模式之前,我们先来了解一下克隆一些知识:
1.clone()方法在Java中从Object类开始就具备,并且作为原生(Native)方法出现。它默认是protected的,因此在被子类提升可见性之前,无法被外界使用。
2.所有需要进行克隆操作的类都必须实现Cloneable接口,这个接口与Serializable接口一样,没有任何需要实现的方法,仅仅是作为一个标示。
3.所有数组都实现了Cloneable接口,并且已经提升了clone()方法的可见性至public,换句话说数组对象是可以直接调用clone()方法的。
4.克隆分为浅拷贝和深拷贝两种,浅拷贝的操作基本上可以理解为只拷贝存储于栈中的内容,包括对象中简单类型的数据、指向其他复杂对象的指针等,但是不会将指向的复杂对象也拷贝一次。
目的:
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
场景:
大话西游中唐僧说到:“人是人他妈生的,妖是妖他妈生的,人妖自然是人妖他妈生的咯”,那Zerg众多可爱……可怕的怪兽们都是谁生的?
早上9:00,Kerrigan从床上起来,看见基地里面一片欣欣向荣的景象觉得心情特别舒畅:一群Drone在卖力的挖水晶搬气体,Zergling、Hydralisk们在精神抖擞的踏着正步(BUG:Hydralisk貌似很难走正步),就连基地刚刚分泌出来的3只Larva(虫族的幼虫)都在屁颠屁颠的使劲蹦跶。
Kerrigan也开始了她虫族女王的工作:看了看水晶和气体存量,指着一只Zergling对Larva说:你变成它吧,再指着另外一只Hydralisk对Larva说:你就变成它吧……
分析:
如果说Zergling的存在是为了锋利的抓牙,Hydralisk的存在是为了强腐蚀性的毒液,那Larva生命的唯一意义就是变成别人,它可以说就是Zerg们“它妈”。用一句OOP的话来说:每个Zerg都是从Larva派生出来的,Larva有一个clone方法,自然从Larva派生出来的对象就具备了一个clone方法,它的作用就是根据已有对象(prototype)去生产出一个新的对象。
我们可以用下面代码来模拟“Kerrigan指着一只Zergling对Larva说:你变成它”这个过程:
图5.1 原型模式的UML图
刚刚说了,Larva存在的唯一目的就是为了变成别人,所以它不具备任何的attack()、patrol()方法,只有一个clone()方法,并且是所有Zerg兵种的父类。在这里为了演示需要,给它赋予了3个额外的方法getName()、setName()和toString(),以便区分各个子类。
/**
* Zerg幼虫,是其他Zerg的父类,实现了Closeable接口
*/
public class Larva implements Cloneable {
private String name = "Larva";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 将Clone方法的可见性从protected提升至public
*/
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String toString() {
return "兵种名称:" + name + ", 当前对象的内存地址为:" + super.toString();
}
}
|
接着,我们建立Zergling和Hydralisk两个子类,在本次演示中,我们只希望知道Zerg是怎么繁殖的,而不需要去战斗,所以子类写的非常简单,仅仅赋予它们名字的差别:
/**
* 模拟Hydralisk
*/
public class Hydralisk extends Larva {
public Hydralisk() {
setName("Hydralisk");
}
}
/**
* 模拟Zergling
*/
public class Zergling extends Larva {
public Zergling() {
setName("Zergling");
}
}
|
到此为止,准备工作还差最后一步就要完成了。要使用原型模式去生产产品,自然就要先有一个原型对象,原型对象怎么来的Prototype不管,是new出来的、由别的工厂建造的、还是实现写在常量中的标本都可以。我个人觉得使用常量标本更加合理一些,请看下面代码:
/**
* 模拟Kerrigan使用原型模式生产Zerg的使用场景
*/
public class Kerrigan {
/**
* 常量:兵种的克隆模版
*/
private static final Larva[] HATCH = new Larva[] { new Hydralisk(), new Zergling() };
/**
* Hydralisk在克隆模版中的序号
*/
private static final int HYDRALISK = 0;
/**
* Zergling在克隆模版中的序号
*/
private static final int ZERGLING = 1;
public static void main(String[] args) throws CloneNotSupportedException {
System.out.println(HATCH[HYDRALISK].clone());
System.out.println(HATCH[HYDRALISK].clone());
System.out.println(HATCH[ZERGLING].clone());
System.out.println(HATCH[ZERGLING].clone());
}
}
|
在上述代码中我们建立了一个常量模版数组:HATCH,里面有Zergling各种兵种的模版,要生产具体兵种的时候,只需要在模版中选择适合的原型(prototype)进行克隆。这样的具备以下特点:
1.继承对象的属性值:其他的构造模式中,对象具备什么属性值(譬如演示中的Name属性),是由类构造时赋值所决定的,一般来说工厂生产出来的产品属性值都具备一致性。而原型模式生产出来的产品,属性值来源于原型对象而不是类,当前对象的属性值是什么样子,克隆对象的属性值就是什么样子,这点是Prototype模式与其他模式使用场景上最大的差异。
2.运行时修改产品列表:Prototype模式不依赖工厂,只需要拿到实例即可创建新的对象,这点比其他模式更为灵活。
3.绕过对象构造:原型模式生产对象的过程中,本质上讲是一个内存复制的过程,因此它是不会调用对象的构造函数的。
展示一下程序的最终运行结果:
图 5.2 克隆的兵种
总结:
Prototype模式中实现起来最困难的地方就是内存复制操作,所幸在Java中提供了clone()方法替我们做了绝大部分事情。在其他语言之中,一种比较简单的方法是可以考虑使用序列化技术(Serilization)来完成对象的复制。
在Java语言中clone()方法完成的是浅拷贝的克隆,如果需要深拷贝,也可以考虑使用序列化来完成,当然这样比起Native的clone()方法来说,效率差了很多,所以更加推荐的方法是针对类中包含的复杂对象情况,重写clone()方法,多次调用父类的clone()来完成,虽然要多写不少代码,但是保证了效率。
在本章中,我们了解到了Zerg们的出生过程,如果说茫茫多的怪兽都是通过原型模式克隆出来的,那独一无二的虫族刀锋女王Kerrigan呢?请继续看构造模式部分的最后一章——单例模式。
- 大小: 5.2 KB
- 大小: 41.1 KB
分享到:
相关推荐
动态调用对象的属性和方法——性能和灵活性兼备的方法 消除由try/catch语句带来的warning 微软的应试题完整版(附答案) 一个时间转换的问题,顺便谈谈搜索技巧 .net中的正则表达式使用高级技巧 (一) C#静态成员和...
当我们具备了这些知识,用户体验过程看起来就是将想法手绘出来,大家一起头脑风暴来探索设计模式以及今后可能的发展方向。接下来,我们创建了交互原型,用以将思维模式可视化展现出来。在整个过程中,我们邀请用户...
电子相册-UI设计 南京航空航天大学 产品设计-课程设计 课题 名称: 电子毕业纪念册设计 课题 时间: 2015·11——2016·1 设 计 者: 学 号: 电子相册-UI设计全文共21页,当前为第1页。 电子相册-UI设计全文共21页,...
根据快速原型法的特点,说明它特别适合于开发探索型、实验型的软件。 3. 如何画分层数据流图? 答: 总的原则是:至顶而下,逐层分解(画分层数据流图)。 比较复杂的系统不能画在一张纸上,逐层分解的画法可以...
最后,我们确定了 6 个元 SE 策略——从 39 个策略中减少——并确定了四个新的元 SE 策略(即系统改革、实物资本开发、循证实践和原型设计),这些策略在之前的 SE 中被忽视了研究。 我们的研究结果扩展和深化了对...
基于多媒体数据库的数据挖掘系统原型.caj 基于小波理论的数据挖掘方法研究.caj 基于属性分类的数据挖掘方法.caj 基于改进Elman网的非线性系统的自适应建模与预估.pdf 基于数据抽取器实现数据挖掘.caj 基于数据挖掘...
基于多媒体数据库的数据挖掘系统原型.caj 基于小波理论的数据挖掘方法研究.caj 基于属性分类的数据挖掘方法.caj 基于改进Elman网的非线性系统的自适应建模与预估.pdf 基于数据抽取器实现数据挖掘.caj 基于数据挖掘...
基于多媒体数据库的数据挖掘系统原型.caj 基于小波理论的数据挖掘方法研究.caj 基于属性分类的数据挖掘方法.caj 基于改进Elman网的非线性系统的自适应建模与预估.pdf 基于数据抽取器实现数据挖掘.caj 基于数据挖掘...
探索式数据挖掘模型的讨论.caj 前向网络bp算法在数据挖掘中的运用.caj 数据挖掘在Internet信息导航系统中的应用研究.caj 数据挖掘技术123.caj 基于粗糙集(Rough set)的数据挖掘及其实现.caj 数据挖掘技术在建模、...