原型设计模式详解
文章目录
前言
在软件系统中,有时需要多次创建某一类型的对象,为了简化创建过程,可以之创建一个对象然后通过克隆的方式复制出多个相同的对象,这就是原型模式的设计思想。常见的复制、粘贴操作中就蕴含了原型模式。本文将通过类图和实例详细介绍原型设计模式。
一、模式定义
Prototype Pattern
原型模式是一种对象型创建模式,用原型实例指定创建对象的种类,并通过复制这些原型创建新的对象。
原型模式允许一个对象再创建另外一个可定制的对象,无需知道任何创建细节。原型模式基本原理是通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象复制原型创建过程。
二、类图结构
Prototype 抽象原型类
抽象原型类是定义具有克隆自己的方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口。
ConcretePrototype 具体原型类
具体原型类实现克隆方法,在克隆方法中返回自己的一个克隆对象
Client 客户类
客户类让一个原型克隆自身,从而创建一个新的对象。 在客户端类中只需要直接实例化或通过工厂方法等方法式创建一个对象,再通过调用该对象的克隆方法复制得到多个相同的对象。
实例分析
深克隆与浅克隆
浅克隆 中复制对象的所有普通成员变量都具有与原来的对象相同的值,而且 所有的对其他对象的引用仍指向原来的对象。浅克隆仅仅复制所考虑的对象,而不复制它所引用的对象,其成员对象不复制。
深克隆 复制对象的所有普通成员变量也都与原来的对象相同的值,引用的其他对象的变量将被只想被复制过的新对象,即原型对象所包含的对象成员也将会被复制。
邮件复制浅克隆
如上图所示,创建Email 类包含一个Attachment对象成员,用于演示深浅克隆的差别。
java 语言中 所有类都是Object 的子类,且Object中提供了克隆方法 clone(),用于创建一个原型对象,使用时只需让类实现Cloneable 接口即可,clone方法由JVM 提供,使用时无需关心。
Email 类代码
public class Email1 implements Cloneable {
private Attachment attachment = null;
public Email1(){
this.attachment = new Attachment();
}
// 复制邮件 克隆函数
public Object clone(){
Email1 copy = null;
try {
copy = (Email1)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return copy;
}
public Attachment getAttachment() {
return attachment;
}
public void display(){
System.out.println("查看邮件");
}
}
Attachment 附件类代码
public class Attachment {
public void download(){
System.out.println("下载附件");
}
}
Client 类代码
public class Client {
public static void mian(String a[]){
Email1 email ,copyEmail;
email = new Email1();
copyEmail = (Email1)email.clone();
System.out.println("email == copyEmail?");
System.out.println(email == copyEmail);
System.out.println("email.getAttachment() == copyEmail.getAttachment()?");
System.out.println(email.getAttachment() == copyEmail.getAttachment());
}
}
Client 中写了mian 方法用于测试,克隆后的对象与原型对象的对象成员是否一致,小伙伴们可以亲自尝试一下,可以看到,对于上述浅克隆的Email 代码 二者的对象成员一定是一致的。
邮件复制深克隆
在复制邮件的同时也复制邮件中的附件内容。
由于Clone()方法 ,实现的浅克隆,所以Email 类想要实现深克隆不需要实现Cloneable接口。 深克隆的思路是通过序列化的方式,将原型Email对象写入流中,因此Email类需要实现Serializable接口。
Email 类实现代码如下 (重点看序列化代码)
public class Email2 implements Serializable {
private Attachment attachment = null;
public Email2(){
this.attachment = new Attachment();
}
// 复制邮件 克隆函数
public Object deepClone() throws Exception ,ClassNotFoundException,OptionalDataException{
// 将当前对象写入对象流
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(this);
// 从对象流中读入对象
ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
public Attachment getAttachment() {
return attachment;
}
public void display(){
System.out.println("查看邮件");
}
}
其他类的代码浅克隆, 小伙伴们可以对浅克隆中的Client 客户端类代码稍作调整,进行再次测试,可以看到 copyEmail对象 和email 对象是不同的,而且他们的attachment 对象成员也是不同的。这意味着 深复制,不仅复制了Email对象,而且还复制了Email的对象成员。
总结
原型设计模式也是一个非常重要的对象设计模式,重点还是要理解深、浅克隆的异同和基本实现思路。原型设计模式也用到了里氏代换的设计思想,来支持更多的具体克隆对象扩展。