创建模式中的原始(Prototype)模式
来源:互联网 发布:现金流量适合比率算法 编辑:程序博客网 时间:2024/04/30 13:56
创建模式中的原始(Prototype)模式
原始模型模式属于对象的创建模式。通过给出一个原始对象来指明所要创建的对象的类型。然后用复制这个原型对象的办法创建出更多同类型的对象。
原始模型模式: Java语言的构件模型直接支持原始模型模式。所有的JavaBean都继承自java.lang.Object,而Object类提供一个clone(),可以将一个JavaBean对象复制一份。但是,这个JavaBean必须实现一个标示接口(Cloneable),标明这个JavaBean支持复制。如果一个对象没有实现这个接口而调用clone()方法,Java编译器就会抛出CloneNotSupportedException异常。
变量、对象以及对象的引用
在Java语言中,对象就是类的实例。在一般情况下,当把一个类实例化时,此类的所有的成员,包括变量和方法,都被复制到属于此数据类型的一个新的实例中去。对象的创建和对象的引用时分隔开来的。
Java对象的复制
java.lang.Object.clone()方法 Java的所有类都是从java.lang.Object类继承而来的。而Object类提供下面的对象的方法对对象进行复制
protected Object clone() 子类当然也可以把这个方法置换掉,提供满足自己需要的复制方法,对象的复制有一个基本问题,就是对象通常都有对其他的对象的引用。当使用Object类的clone()方法来复制一个对象时,此对象对其他对象的引用也同时会被复制一份。Java语言提供的Cloneable接口只起一个作用,就是在运行时期通知Java虚拟机可以安全地在这个类上使用clone()方法,通过调用这个clone()方法可以得到一个对象的复制。由于Object类本身并不实现Cloneable接口,因此如果所考虑的类没有实现Cloneable接口时,调用clone方法会抛出CloneNotaSupportedException异常。of course ,系统可以在PandaToClone里面置换掉java.lang.Object提供的clone()方法,以便控制复制的过程。
package com.test.clone;
public class PandaToClone implements Cloneable {
private int height;
private int weight;
private int age;
public PandaToClone(int height, int weight) {
this.age = 0;
this.height = height;
this.weight = weight;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/*public Object clone() {
PandaToClone temp = new PandaToClone(height, weight);
temp.setAge(age);
return (Object)temp;
}*/
public static void main(String[] args) throws CloneNotSupportedException {
PandaToClone thisPanda = new PandaToClone(15, 25);
PandaToClone thatPanda = (PandaToClone)thisPanda.clone();
System.out.println("Age of thisPanda: " + thisPanda.getAge());
System.out.println(" height: " + thisPanda.getHeight());
System.out.println(" weight: " + thisPanda.getWeight());
System.out.println("Age of thatPanda: " + thatPanda.getAge());
System.out.println(" height: " + thatPanda.getHeight());
System.out.println(" weight: " + thatPanda.getWeight());
System.out.println(thisPanda == thatPanda);
}
}
Age of thisPanda: 0
height: 15
weight: 25
Age of thatPanda: 0
height: 15
weight: 25
false
克隆满足的条件:
clone()方法将对象复制了一份并返回给调用者。所谓“复制”的含义与clone()方法时怎么实现的有关。一般而言,clone()方法满足以下的描述:
◆ 对任何对象x,都有:x.clone() != x。换言之,克隆对象与原对象不是同一个对象。
◆ 对任何的对象x,都有:x.clone.getClass == x.getClass(),换言之,克隆对象与原对象的类型一样。
◆ 如果对象的x的equals()方法定义恰当的话,那么x.clone().equals(x)应当是成立的。语言的设计师在设计自己的clone()方法时,也应当遵守这三个条件。
原始模型模式的结构:
原始模型模式有两种表现形式:第一种是简单形式,第二种是登记形式。这两种表现形式仅仅是原始模型模式的不同实现,但是由于他们的区别影响了模式结构的细节。
简单形式的原始模型模式
package com.test.clone;
public interface Prototype extends Cloneable {
Object clone();
}
package com.test.clone;
public class ConcretePrototype implements Prototype {
/**
* 克隆方法
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
package com.test.clone;
public class Client {
private static Prototype prototype;
public static void main(String[] args) {
prototype = new ConcretePrototype();
Prototype p2 = (Prototype)prototype.clone();
}
}
这种形式涉及到三个角色:
◆ 客户(Client)角色:客户类提出创建对象的请求。
◆ 抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需要的接口。
◆ 具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所需求的接口。
登记形式的原始模型模式
第二种形式的原始模型模式
package com.test.clone;
import java.util.Vector;
public class PrototypeManager {
private Vector<Prototype> objects = new Vector<Prototype>();
/**
* 聚集管理方法:增加一个新的对象
* @param object
*/
public void add(Prototype object) {
objects.add(object);
}
/**
* 聚集管理方法:取出聚集中的一个对象
* @param i
* @return
*/
public Prototype get(int i) {
return (Prototype)objects.get(i);
}
/**
* 聚集管理方法:给出聚集的大小
* @return
*/
public int getSize() {
return objects.size();
}
}
两种形式的比较:
如果需要创建的原型对象数目较少而且比较固定的话,可以采用第一种形式,也即简单形式的原始模型模式。在这种情况下,原型对象的引用可以由客户端自己保存。
如果要创建的原型对象数目不固定的话,可以采取第二种形式,也即登记形式的原始模型模式。在这种情况下,客户端并不保存对原型对象的引用,这个任务被交给管理员对象。在复制一个对象之前,客户端可以查看管理员对象是否已经有一个满足要求的原型对象。如果有,可以直接从管理员类取得这个对象的引用;如果没有,客户端就需要自行复制此原型对象。
模式的实现:深复制(深克隆)和浅复制(浅克隆)
浅复制(浅克隆): 被复制对象的所有变量都含有与原来的对象相同的值,而所有的其他对象的引用都仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深复制(深克隆): 被复制对象的所有的变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过来的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用对象都复制了一遍,而这种对被引用的对象的复制叫做间接复制。
深复制要深入多少层,是一个不易确定的问题。在决定以深复制方式复制一个对象的时候,必须决定对间接复制的对象采取浅复制还是继续采用深复制。因此,在采取深复制是,需要决定多深才算深,此外,在复制的过程中,很可能会出现循环引用的问题,必须小心处理。
把对像写到流里的过程是串行化(Serilization)过程,但是在Java程序师的圈子里又非常形象地成为“冷冻”或者“腌咸菜(pickling)过程”;而把对像从流里读出来的过程叫做并行化(Deserialization)过程则叫做“解冻”或者“回鲜(depicking)”过程。应当指出写到流里的是一个对象的拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。
在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里)(腌成咸菜),再从流里(把咸菜回鲜),便可以重建对象。
这样做的前提是:对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象是否设成transient,从而将之排除在复制过程之外。
浅复制虽然比深复制更容易实现,因为Java语言的所有类都会继承一个clone()方法,而这个clone() 方法所做的正是浅复制。
package com.test.clone;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DeepCloneStudent implements Serializable {
private int id;
private String name;
public Object deepClone() throws Exception {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return oi.readObject();
}
public static void main(String[] args) throws Exception {
DeepCloneStudent st = new DeepCloneStudent();
st.id = 1;
st.name = "li";
DeepCloneStudent st2 = (DeepCloneStudent)st.deepClone();
System.out.println(st2.id);
System.out.println(st2.name);
}
}
使用原始模型模式的场景:假设一个系统的产品类是动态加载的,而且产品具有一定的等级结构。
原始模型模式的优点和缺点:
抽象工厂模式有许多与原始模型模式和建造模式相同的效果,包括客户端不知道具体产品类,而只知道抽象产品类,客户端不需要知道这么多产品的具体产品名称。如果有新的产品类加入,客户端不需要进行改造就可直接使用。
优点:
◆ 原始模型模式允许动态地增加或减少产品类。由于创建产品类实例的方法是产生类内部具有的,因此,增加新产品对整个结构没有影响。
◆ 原始模型模式提供简化的创建结构。工厂方法模式常常需要一个与产品类等级结构相同的等级结构,而原始模型模式就不需要这样。对于Java设计师来说,原始模型模式又有其特有的方便之处,因为Java语言天生就将原始模型模式设计到了语言模型里面。善于利用原始模型模式和Java语言的特点,可以事半功倍。
◆ 具有给一个应用软件动态加载功能的能力。例如,一个分析Web服务器的记录文件的应用软件,针对每一种记录文件格式,都可以由一个相应的“格式类”负责。如果出现了应用软件所不支持的新的Web服务器,只需要提供一个格式类的克隆,并在客户端登记即可,而不必给每个软件的用户提供一个全新的软件包。
◆ 产品类不需要非得有任何事先确定的等级结构,因为原始模型模式适用于任何等级结构。
原始模型模式最主要的缺点是每一个类都必须配备一个克隆方法。配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类来说不是很难,而对于已经有的类不一定很容易,特别是当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
Java的串行化功能:
在Java语言从1.0升级到1.1版本时,Java语言的功能在很多方面得到了很大的提高,串行化(Serialization)就是那时候引进来的新的功能。用一句话来讲,串行化使得一个程序可以把一个完整的对象写到一个Byte流里面,或者从一个Byte流里面读出一个事先存储在里面的完整对象;串行化可以把Java对象和原始数据类型转换成一个适合于某种网络或文件系统的Byte流。
- 创建模式中的原始(Prototype)模式
- (C++设计模式) ------原始模型模式 Prototype -- 创建型模式
- 原始模型(Prototype)模式学习笔记
- 《Java与模式》选读“原始模型(Prototype)模式”
- 浅谈 java 设计模式--原始模型模式(Prototype pattern)
- 创建模式:Prototype模式
- 创建型模式-----原型模式(Prototype)
- Prototype - 原型创建模式
- 设计模式:创建型模式:原型模式(prototype pattern)
- Prototype 原型(创建型模式)
- 6.Prototype(创建型模式)
- 创建型模式:Prototype(原型)
- Prototype 原型(创建型模式) 笔记
- 设计模式--创建型-Prototype(原形)
- java原型模式(Prototype)-创建型
- 四、原型模式Prototype(创建型)
- 创建型:原型模式(Prototype)
- 《Java与模式》学习笔记之八---原始模型模式(Prototype Pattern)
- Spring 详解
- 处女贴
- 使用c#开发mapserver之五classObj
- 演示更流畅 减小幻灯片文件的存储大小
- jsp中过滤不良信息问题
- 创建模式中的原始(Prototype)模式
- 亲爱的~如果我在错误的时间遇见了对的你~你是否愿意等我一程?
- 【C++学习】学习const
- 做WinForm程序,在通知区域加入NotifyIcon,程序退出后不消失的解决
- 创建模式中的单例模式
- ENTER_FRAME事件简单控制往返运动
- 优化学习过程
- servlet和tomcat相关知识
- C++ 实现MergeSort算法