原形模式

模式定义

  • 原型模式(Prototype Pattern):原型模式是一种对象创建型模式,用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。原型模式允许一个对象再创建另外一个可定制的对象,无须知道任何创建的细节。
  • 原型模式的基本工作原理是通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝原型自己来实现创建过程。
  • 工作原理:将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程:
    创建新对象(也称为克隆对象)的工厂就是原型类自身,工厂方法由负责复制原型对象的克隆方法来实现。
    通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,每一个克隆对象都是独立的。
    通过不同的方式对克隆对象进行修改以后,可以得到一系列相似但不完全相同的对象。

模式结构

原型模式结构

  • Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。
  • ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
  • Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。由于客户类针对抽象原型类Prototype编程,因此用户可以根据需要选择具体原型类,系统具有较好的可扩展性,增加或更换具体原型类都很方便。

模式分类

浅克隆

在浅克隆中,被复制对象的所有普通成员变量都具有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅克隆仅仅复制所考虑的对象,而不复制它所引用的成员对象,也就是其中的成员对象并不复制。

浅克隆

深克隆

在深克隆中被复制对象的所有普通成员变量也都含有与原来的对象相同的值,除去那些引用其他对象的变量。哪些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。在深克隆中,除了对象本身被复制外,对象包含的引用也被复制,也就是其中的成员对象也将复制。

深克隆

模式实例

实例一:邮件复制(浅克隆)

由于邮件对象包含的内容较多(如发送者、接收者、标题、内容、日期、附件等),某系统中现需要提供一个邮件复制功能,对于已经创建好的邮件对象,可以通过复制的方式创建一个新的邮件对象,如果需要改变某部分内容,无须修改原始的邮件对象,只需要修改复制后得到的邮件对象即可。使用原型模式设计该系统。在本实例中使用浅克隆实现邮件复制,即复制邮件(Email)的同时不复制附件(Attachment)。

邮件复制(浅克隆)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 附件类 Attachment
public class Attachment {
public void download(){
System.out.println("下载附件");
}
}

// 具体原型类 Email(邮件类)
public class Email implements Cloneable {
private Attachment attachment = null;
public Email(){
this.attachment = new Attachment();
}
public Object clone(){
Email clone = null;
try {
clone = (Email)super.clone();
} catch (CloneNotSupportedException e) {
System.out.println("clone failure");
}
return clone;
}
public Attachment getAttachment(){
return this.attachment;
}
public void display(){
System.out.println("查看邮件");
}
}

// 客户端测试类 Client
public class Client {
public static void main(String[] args) {
Email email,copyEmail;
email = new Email();
copyEmail = (Email)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());
}
}

实例二:邮件复制(深克隆)

使用深克隆实现邮件复制,即复制邮件的同时复制附件。

邮件复制(深克隆)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 附件类 Attachment
import java.io.Serializable;

public class Attachment implements Serializable {
public void download(){
System.out.println("下载附件");
}
}

// 具体原型类 Email(邮件类)
import java.io.*;

public class Email implements Serializable {
private Attachment attachment = null;
public Email(){
this.attachment = new Attachment();
}
public Object deepclone() throws IOException, 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 this.attachment;
}
public void display(){
System.out.println("查看邮件");
}
}

// 客户端测试类 Client
public class Client {
public static void main(String[] args) {
Email email,copyEmail = null;
email = new Email();
try {
copyEmail = (Email)email.deepclone();
} catch (Exception e) {
e.printStackTrace();
}

System.out.println("email == copyEmail?");
System.out.println(email == copyEmail);

System.out.println("email.getAttachment == copyEmail.getAttachment?");
System.out.println(email.getAttachment() == copyEmail.getAttachment());
}
}

Email 作为具体原型类,由于实现的是深克隆,无须使用 Objectclone() 方法,因此无须实现 Cloneable 接口;可以通过序列化的方式实现深克隆,由于要将 Email 类型的对象写入流中,因此Email类需要实现 Serializable 接口。
作为 Email 类的成员对象,在深克隆中,Attachment 类型的对象也将被写入流中,因此 Attachment 类也需要实现 Serializable 接口。

模式优缺点

原型模式的优点

  • 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过一个已有实例可以提高新实例的创建效率。
  • 可以动态增加或减少产品类。
  • 原型模式提供了简化的创建结构。
  • 可以使用深克隆的方式保存对象的状态。

原型模式的缺点

  • 需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了“开闭原则”。
  • 在实现深克隆时需要编写较为复杂的代码
文章目录
  1. 1. 模式定义
  2. 2. 模式结构
  3. 3. 模式分类
    1. 3.1. 浅克隆
    2. 3.2. 深克隆
  4. 4. 模式实例
    1. 4.1. 实例一:邮件复制(浅克隆)
    2. 4.2. 实例二:邮件复制(深克隆)
  5. 5. 模式优缺点
    1. 5.1. 原型模式的优点
    2. 5.2. 原型模式的缺点

20160528-DesignPattern-4/

本页二维码