设计模式-原型模式.ppt_第1页
设计模式-原型模式.ppt_第2页
设计模式-原型模式.ppt_第3页
设计模式-原型模式.ppt_第4页
设计模式-原型模式.ppt_第5页
已阅读5页,还剩22页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

设计模式 原型(Prototype)模式,Session3 By 佘丹,1st Jul 2008,原型(Prototype)模式,通过给出一个原型对象来指明所要创建的对象类型,然后用拷贝这个原型对象的办法创建出更多的同类型对象。 孙大圣的毫毛 孙悟空在与黄风怪的战斗中,“使一个身外身的手段:把毫毛揪下一把,用口嚼得粉碎,望上一喷,叫声变,变有百十个行者,都是一样得打扮,各执一根铁棒,把那怪围在空中。”换而言之,孙悟空可以根据自己的形象,拷贝出很多“身外身”来。 孙悟空这种身外身的手段在面向对象设计领域里叫原型(Prototype)模式。,1,Java对原型模式的支持,在Java里面,我们可以通过Clone()方法实现原型模式。任何类,只要想支持克隆,必须实现Cloneable接口。Cloneable接口中有Clone方法,可以在类中复写实现自定义的克隆方法。克隆的实现方法有三种:浅拷贝、深拷贝和完全拷贝。 (1)浅拷贝 被拷贝对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅拷贝所考虑的对象,而不拷贝它所引用的对象。 (2)深拷贝 被拷贝对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被拷贝过的新对象,而不再是原有的那些被引用的对象。换言之,深拷贝把要拷贝的对象所引用的对象都拷贝了一遍。 (3)完全拷贝 完全拷贝不仅把要拷贝的对象所直接引用的对象都拷贝了一遍, 还把该对象间接引用到的所有对象也都拷贝了一遍。这是最彻底的一种拷贝。,2,Java的clone()方法,Clone protected Object clone() throws CloneNotSupportedException This method may be called to create a new copy of the Object. The typical behavior is as follows: o = o.clone() is false o.getClass() = o.clone().getClass() is true o.equals(o) is true However, these are not strict requirements, and may be violated if necessary. Of the three requirements, the last is the most commonly violated, particularly if the subclass does not override equals(Object) 55 . If the Object you call clone() on does not implement Cloneable (which is a placeholder interface), then a CloneNotSupportedException is thrown. Notice that Object does not implement Cloneable; this method exists as a convenience for subclasses that do. Objects implementation of clone allocates space for the new Object using the correct class, without calling any constructors, and then fills in all of the new field values with the old field values. Thus, it is a shallow copy. However, subclasses are permitted to make a deep copy. All array types implement Cloneable, and override this method as follows (it should never fail): public Object clone() try super.clone(); catch (CloneNotSupportedException e) throw new InternalError(e.getMessage(); ,2,Java的clone()方法,clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足: 对任何的对象x,都有x.clone() !=x 克隆对象与原对象不是同一个对象 对任何的对象x,都有x.clone().getClass()=x.getClass() 克隆对象与原对象的类型一样 如果对象x的equals()方法定义恰当,那么 x.clone().equals(x)应该成立。 Java中对象的克隆 为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。 在派生类中覆盖基类的clone()方法,并声明为public。 在派生类的clone()方法中,调用super.clone()。 在派生类中实现Cloneable接口。,3,Java的类拷贝实现代码,class Student implements Cloneable String name; int age; Student(String name,int age) =name; this.age=age; public Object clone() Object o=null; try o=(Student)super.clone();/Object中的clone()识别出你要复制的是哪一个对象。 catch(CloneNotSupportedException e) System.out.println(e.toString(); return o; public static void main(String args) Student s1=new Student(“zhangsan”,18); Student s2=(Student)s1.clone(); =“lisi”; s2.age=20; System.out.println(“name=”++“,”+“age=”+s1.age);/修改学生2后,不影响学生1的值。 ,为什么我们在派生类中覆盖Object的clone()方法时, 一定要调用super.clone()呢?在运行时刻,Object中的 clone()识别出你要复制的是哪一个对象,然后为此对象 分配空间,并进行对象的复制,将原始对象的内容一一 复制到新对象的存储空间中。 继承自java.lang.Object类的clone()方法是浅复制。 后面的代码可以证明。,浅拷贝,3,Java的类拷贝实现代码,class Professor String name; int age; Professor(String name,int age) =name; this.age=age; ,class Student implements Cloneable String name;/常量对象。 int age; Professor p;/学生1和学生2的引用值都是一样的。 Student(String name,int age,Professor p) =name; this.age=age; this.p=p; public Object clone() Student o=null; try o=(Student)super.clone(); catch(CloneNotSupportedException e) System.out.println(e.toString(); /o.p=(Professor)p.clone(); return o; ,public static void main(String args) Professor p=new Professor(“wanGWu“,50); Student s1=new Student(“zhangsan“,18,p); Student s2=(Student)s1.clone(); =“lisi“; s2.p.age=30; System.out.println(“name=“++“,“+“age=“+s1.p.age); /学生1的教授为lisi,age为30,被改了 ,浅拷贝,3,Java的类拷贝实现代码,class Professor implements Cloneable String name; int age; Professor(String name,int age) =name; this.age=age; public Object clone() Object o=null; try o=super.clone(); catch(CloneNotSupportedException e) System.out.println(e.toString(); return o; ,class Student implements Cloneable String name;/常量对象。 int age; Professor p;/学生1和学生2的引用值都是一样的。 Student(String name,int age,Professor p) =name; this.age=age; this.p=p; public Object clone() Student o=null; try o=(Student)super.clone(); catch(CloneNotSupportedException e) System.out.println(e.toString(); o.p=(Professor)p.clone(); return o; ,public static void main(String args) Professor p=new Professor(“wanGWu”,50); Student s1=new Student(“zhangsan”,18,p); Student s2=(Student)s1.clone(); =“lisi”; s2.p.age=30; System.out.println(“name=”++“,”+“age=”+s1.p.age);/学生1的教授不改变 ,深拷贝,3,Java的类拷贝实现代码,class Professor implements Serializable String name; int age; Professor(String name,int age) =name; this.age=age; ,class Student implements Serializable String name;/常量对象。 int age; Professor p;/学生1和学生2的引用值都是一样的。 Student(String name,int age,Professor p) =name; this.age=age; this.p=p; public Object fullClone() throws IOException, OptionalDataException,ClassNotFoundException /将对象写到流里 ByteArrayOutoutStream 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) Professor p=new Professor(“wangwu“,50); Student s1=new Student(“zhangsan“,18,p); Student s2=(Student)s1.fullClone(); =“lisi“; s2.p.age=30; System.out.println(“name=“++“,“+“age=“+s1.p.age); /学生1的教授不改变。,完全拷贝,在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝) 写到一个流里(腌成干菜),再从流里读出来(把干菜回鲜),便可以重建对象。,4,Prototype模式的结构,客户(Client)角色: 客户类提出创建对象的请求。 抽象原型(Prototype)角色: 这是一个抽象角色,通常由一个接口类或抽象类实现。此角色给出所有的具体原型 类所需的接口。在Java中,抽象原型角色通常实现了Cloneable接口。 具体原型(Concrete Prototype)角色: 被复制的对象。此角色需要实现抽象原型角色所要求的接口。,4.1 Prototype模式实现 - 抽象原型,public abstract class AbstractSpoon implements Cloneable String spoonName; public void setSpoonName(String spoonName) this.spoonName = spoonName; public String getSpoonName() return this.spoonName; public Object clone() Object object = null; try object = super.clone(); catch (CloneNotSupportedException exception) System.err.println(“AbstractSpoon is not Cloneable“); return object; ,4.2 Prototype模式实现 - 具体原型,public class SaladSpoon extends AbstractSpoon public SaladSpoon() setSpoonName(“Salad Spoon“); ,public class SoupSpoon extends AbstractSpoon public SoupSpoon() setSpoonName(“Soup Spoon“); ,4.3 Prototype模式实现 - 客户,public class Client /* * param args */ public static void main(String args) AbstractSpoon spoon1 = new SoupSpoon(); AbstractSpoon spoon2 = (AbstractSpoon) spoon1.clone(); System.out.println(spoon2.getSpoonName(); AbstractSpoon spoon3 = new SaladSpoon(); AbstractSpoon spoon4 = (AbstractSpoon) spoon3.clone(); System.out.println(spoon4.getSpoonName(); ,5,带原型管理器的原型模式,客户(Client)角色: 客户端类向原型管理器提出创建对象的请求。 抽象原型(Prototype)角色: 这是一个抽象角色,通常由一个接口或抽象类实现。 此角色给出所有的具体原型类所需的接口。在Java中,抽象原型角色通常实现了Cloneable接口。 具体原型(Concrete Prototype)角色: 被复制的对象。此角色需要实现抽象的原型角色所要求的接口。 原型管理器(Prototype Manager)角色: 创建具体原型类的对象,并记录每一个被创建的对象。,5.1 带原型管理器的原型模式实现 原型管理器,import java.util.HashMap; public class SpoonManager private HashMap hm = null; private static SpoonManager spoonManager = null; private SpoonManager() hm = new HashMap(); public static synchronized SpoonManager getSpoonManager() if(spoonManager = null) spoonManager = new SpoonManager(); return spoonManager; public void register(String name, Object prototype) hm.put(name,prototype); public void unRegister(String name) hm.remove(name); public Object getSpoon(String name) Object o = null; if(hm.containsKey(name) o = hm.get(name); else try/自动查找原型管理器里不存在的类,并动态生成它 o = Class.forName(name).newInstance(); this.register(name,o); catch(Exception e) System.out.println(“class “+name+“ dont define “+e.getMessage(); e.printStackTrace(); return (AbstractSpoon)o).clone(); ,5.2 带原型管理器的原型模式实现 客户,public class Client /* * param args */ public static void main(String args) AbstractSpoon soupSpoon = new SoupSpoon(); AbstractSpoon saladSpoon = new SaladSpoon(); SpoonManager spoonManager = SpoonManager.getSpoonManager(); spoonManager.register(“prototype.test.SoupSpoon“, soupSpoon); spoonManager.register(“prototype.test.SaladSpoon“, saladSpoon); AbstractSpoon soupSpoon2 = (AbstractSpoon) spoonManager.getSpoon(“prototype.test.SoupSpoon“); AbstractSpoon saladSpoon2 = (AbstractSpoon) spoonManager.getSpoon(“prototype.test.SaladSpoon“); System.out.println(soupSpoon.hashCode(); System.out.println(soupSpoon2.hashCode(); System.out.println(saladSpoon.hashCode(); System.out.println(saladSpoon2.hashCode(); ,6, JavaScript中的prototype应用,下面是一个比较实际的web应用中的例子,通过现有的dom元素对象,创建了一个新的副本。这个副本dom元素并没有使用document.createElement方法创建。 TestDiv var testClone = document.getElementById(test).cloneNode(true); document.body.appendChild(testClone); ,6, JavaScript中的prototype应用,浅拷贝,function Writer (name, sex) = name; this.sex = sex; function Book (name, pages, price, writer) = name; this.pages = pages; this.price = price; this.writer = writer; Btotype.clone = function () /深拷贝浅拷贝的区别就在这个function里 return new Book(, this.pages, this.price, this.writer); var writer = new Writer(佘丹, 男); var bookName = 深入解析原型模式; var myBook = new Book(bookName, 611, 70, writer); var otherBook = myBook.clone(); myB = 不是深入解析原型模式; /值类型的修改不会相互影响 alert(myB,otherB);/所以这里打印:不是深入解析原型模式,深入解析原型模式 myB = 不是佘丹; /引用类型的修改会相互影响,因为他们引用同个内存地址 alert(myB, otherB);/所以这里打印:不是佘丹,不是佘丹,6, JavaScript中的prototype应用,深拷贝,function Writer (name, sex) = name; this.sex = sex; function Book (name, pages, price, writer) = name; this.pages = pages; this.price = price; this.writer = writer; Btotype.clone = function () /深拷贝浅拷贝的区别就在这个function里 var writer = new Writer(,this.writer.sex); return new Book(, this.pages, this.price, writer); var writer = new Writer(佘丹, 男); var bookName = 深入解析原型模式; var myBook = new Book(bookName, 611, 70, writer); var otherBook = myBook.clone(); myB = 不是深入解析原型模式; /值类型的修改不会相互影响 alert(myB,otherB);/所以这里打印:不是深入解析原型模式,深入解析原型模式 myB = 不是佘丹; /深拷贝,引用已经指向不同内存地址,修改不会相互影响 alert(myB, otherB);/所以这里打印:不是佘丹,佘丹,6, JavaScript中的prototype应用,原型管理器,StyleTest function StyleItem (fontSize, color) /类定义 this.fontSize = fontSize; this.color = color; StyleItotype.clone = function () return fontSize:this.fontSize, color:this.color var StyleManager = /原型管理器 getStyle: function (key) if (thiskey) return thiskey.clone(); ; /预创建类可能的状态集合对象 StyleManagerbig = new StyleItem(16px, #000); StyleManagernormal = new StyleItem(14px, #333); StyleManagersmall = new StyleItem(12px, #666); /无需再通过new来创建StyleItem类的对象了 var el = document.getElementById(styletest); var style = StyleManager.getStyle(small); for (var k in style)el.stylek = stylek; ,7, 深入JavaScript的prototype,Javascript中的面向对象机制是通过prototype实现的,在new一个对象的时候,其实并没有为每一个对象创建每个prototype成员的副本,而是将对象成员指针指向prototype成员,下面程序可以验证这点:,function Test () Ttotype.alert = function () alert(test); var test1 = new Test(); var test2 = new Test(); alert(test1.alert = test2.alert); totype.alert = function () alert(test1); test2.alert();,7, 深入JavaScript的prototype,此外,JScript中对象的prototype属性,是用来返回对象类型原型的引用的。所有 JScript 内部对象都有只读的 prototype 属性 ,但可以向其原型中动态添加功能(属性和方法),而且对象的新实例会“继承”赋予该对象原型的操作。 下面是三个经典的prototype属性的使用示例。,1、为脚本环境内建对象添加方法: Stotype.trim() return this.replace(/(s )|(s $)/g, “); ,2、为用户自定义类添加方法: function Tes

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论