[把你的理性思维慢慢变成条件反射]
本文,我们讲介绍原型模式,文章主题结构与上位一致。惯例,先来看看我们示例工程的环境:
操作系统:win7 x64
其他软件:eclipse mars,jdk7
-------------------------------------------------------------------------------------------------------------------------------------
经典问题:
对象复制,克隆。思路分析:
要点一:支持浅克隆。
要点二:支持深克隆。
示例工程:
错误写法:
创建Templet.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype;
public class Window {
public static void main(String[] args) {
Templet a = new Templet("TempletA");
a.setContext("AAAAA");
a.setTime("010101");
a.setCompany("CompanyA");
Templet b = a;
b.setName("TempletB");
Templet c = a;
c.setName("TempletC");
a.display();
b.display();
c.display();
System.out.println(a.hashCode());
System.out.println(b.hashCode());
System.out.println(c.hashCode());
}
}
错误原因:
首先,我们先观察上面main方法输出内容:
name:TempletC,context:AAAAA,time:010101,company:CompanyA
name:TempletC,context:AAAAA,time:010101,company:CompanyA
name:TempletC,context:AAAAA,time:010101,company:CompanyA
17198255
17198255
17198255
ABC三个对象在内存当中的地址完全相同,即代表同一个对象。(这部分概念非常基础,请各位看官牢记)。
推荐写法(1):浅克隆(值类型)
创建Prototype.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.one;
public abstract class Prototype {
private String id;
public Prototype(String id){
this.id=id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public abstract Prototype Clone();
}
创建ConcretePrototypeA文件,具体内容如下:
package com.csdn.ingo.gof_prototype.one;
public class ConcretePrototypeA extends Prototype implements Cloneable {
public ConcretePrototypeA(String id) {
super(id);
}
@Override
public Prototype Clone() {
return (Prototype) this.clone();
}
@Override
public Object clone() {
ConcretePrototypeA cpa = null;
try {
cpa = (ConcretePrototypeA) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return cpa;
}
}
创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.one;
public class Window {
public static void main(String[] args) {
ConcretePrototypeA a = new ConcretePrototypeA("ingo");
ConcretePrototypeA b = (ConcretePrototypeA)a.Clone();
System.out.println(a.hashCode());
System.out.println(b.hashCode());
}
}
观察输出:
1149197
20761102
推荐写法(2):浅克隆(引用类型)
创建Collection.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.two;
import com.csdn.ingo.gof_prototype.one.ConcretePrototypeA;
public class Collection implements Cloneable {
private String prop1;
private String prop2;
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public String getProp2() {
return prop2;
}
public void setProp2(String prop2) {
this.prop2 = prop2;
}
@Override
public Object clone() {
Collection co = null;
try {
co = (Collection) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return co;
}
}
创建ConcretePrototypeA.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.two;
public class ConcretePrototypeA extends Prototype implements Cloneable {
private Collection collection =new Collection();
public Collection getCollection() {
return collection;
}
public void setCollection(Collection collection) {
this.collection = collection;
}
public ConcretePrototypeA(String id) {
super(id);
}
@Override
public Prototype Clone() {
return (Prototype) this.clone();
}
@Override
public Object clone() {
ConcretePrototypeA ca = null;
try {
ca = (ConcretePrototypeA) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return ca;
}
}
创建Prototype.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.two;
public abstract class Prototype {
private String id;
public Prototype(String id){
this.id=id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public abstract Prototype Clone();
}
创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.two;
public class Window {
public static void main(String[] args) {
ConcretePrototypeA a = new ConcretePrototypeA("ingo");
ConcretePrototypeA b = (ConcretePrototypeA)a.Clone();
Collection ca = a.getCollection();
ca.setProp1("a1");
ca.setProp2("a2");
Collection cb = b.getCollection();
cb.setProp1("b1");
cb.setProp2("b2");
System.out.println(a.hashCode());
System.out.println(b.hashCode());
System.out.println(a.getCollection().hashCode());
System.out.println(b.getCollection().hashCode());
}
}
观察输出:
1396421
15105042
31164770
31164770
推荐写法(3):深克隆(专用)
创建Colleation.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.three;
import com.csdn.ingo.gof_prototype.two.ConcretePrototypeA;
public class Collection implements Cloneable{
private String date;
private String company;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
@Override
public Object clone(){
Collection ca = null;
try {
ca = (Collection) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return ca;
}
@Override
public String toString() {
return "Collection [date=" + date + ", company=" + company + "]";
}
}
创建Prototype.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.three;
public class Prototype implements Cloneable {
private String name;
private Collection work;
public Prototype(String name){
this.name = name;
work = new Collection();
}
private Prototype(Collection work){
this.work = (Collection)work.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection getWork() {
return work;
}
public void setWork(Collection work) {
this.work = work;
}
public void setWke(String date,String company){
work.setDate(date);
work.setCompany(company);
}
@Override
public String toString() {
return "Prototype [name=" + name + ", work=" + work.toString() + "]";
}
@Override
public Object clone(){
Prototype ca = new Prototype(this.work);
ca.setName(name);
return ca;
}
}
创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.three;
public class Window {
public static void main(String[] args) {
Prototype a = new Prototype("ingo");
System.out.println(a.hashCode());
a.setWke("01", "aaa");
Prototype b = (Prototype)a.clone();
System.out.println(b.hashCode());
b.setWke("02", "bbb");
Prototype c = (Prototype)a.clone();
System.out.println(c.hashCode());
c.setWke("03", "ccc");
System.out.println(a.toString());
System.out.println(b.toString());
System.out.println(c.toString());
}
}
推荐写法(4):深克隆(通用)
创建Collection.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.four;
import java.io.Serializable;
public class Collection implements Serializable {
private static final long serialVersionUID = 1L;
private String date;
private String company;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
@Override
public Object clone() {
Collection ca = null;
try {
ca = (Collection) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return ca;
}
@Override
public String toString() {
return "Collection [date=" + date + ", company=" + company + "]";
}
}
创建Prototype.java文件,具体内容如下;
package com.csdn.ingo.gof_prototype.four;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Prototype implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private Collection work;
public Prototype(String name) {
this.name = name;
work = new Collection();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection getWork() {
return work;
}
public void setWork(Collection work) {
this.work = work;
}
public void setWke(String date, String company) {
work.setDate(date);
work.setCompany(company);
}
@Override
public String toString() {
return "Prototype [name=" + name + ", work=" + work.toString() + "]";
}
public Prototype clone() {
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(bao);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois;
ois = new ObjectInputStream(bis);
return (Prototype) ois.readObject();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_prototype.four;
public class Window {
public static void main(String[] args) {
Prototype a = new Prototype("ingo");
System.out.println(a.hashCode());
a.setWke("01", "aaa");
Prototype b = (Prototype)a.clone();
System.out.println(b.hashCode());
b.setWke("02", "bbb");
Prototype c = (Prototype)a.clone();
System.out.println(c.hashCode());
c.setWke("03", "ccc");
System.out.println(a.toString());
System.out.println(b.toString());
System.out.println(c.toString());
}
}<span style="font-family:Microsoft YaHei;font-size:14px;">
</span>
问题:浅克隆与深克隆的区别?
浅克隆:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。换句话说:对象成员变量中的简单类型都被复制,而引用对象类型,只复制引用,仍然指向原有对象,该对象仍然只有一份。深克隆:被复制对象的所有变量都含有与原来的对象相同的值,所有的对其他对象的引用也复制一份引用的对象。换句话说:对象成员变量中的简单类型都被复制,而引用对象类型,不止复制引用,而是将引用对象也复制一份。
模式总结:
标准UML结构图:
概念总结:
原型模式:用原型实例指定创建对象的种类,并且通过开配这些原型创建新的对象。
组成部分:Prototype(原型类),ConcretePrototype(具体子类)两部分组成。
注:本文仅以Java为例说明,其他语言的原型模式,请各位看官自行学习。
反思:
应用场景:
- 创建相似的对象。
- 在上面的基础之上,创建新对象的花费资源较多,耗时较长的场景。
- 对象变化较小,并需要长时间保存时,在系统内创建备份时。
- 对象中含有组合属性,并且对象数量较少,考虑执行效率时。
优点:
- 当对象较为复杂,通过原型模式可以简化创建过程,提高创建效率。
- 扩展性好。客户端直接与抽象类进行交互,提高了双方的灵活性,扩展性。
- 提供深克隆,浅克隆两种方式供其使用。
缺点:
- 必须要为每一个对象创建一个克隆方法,克隆对象的任何改变,将直接违反“开闭原则”。
- 深克隆的过程需要IO等多个复杂过程。需要及时处理异常情况。
- 深层嵌套的克隆难于管理及实现。
-------------------------------------------------------------------------------------------------------------------------------------
至此,被说了很多遍的设计模式---原型模式 结束
参考资料:
图书:《大话设计模式》
其他博文:http://blog.csdn.NET/lovelion/article/details/7563445