Fork me on GitHub

设计模式之原型模式

设计模式之原型模式

1. 什么是原型模式

Prototype模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用Prototype模式创建的实例,具有与原型一样的数据。

换句话说原型模式就是通过复制现有实例来创建新的实例,无须知道相应类的信息。

原型模式的结构:

1

优缺点

优点:

  • 使用原型模式创建对象比直接new一个对象更有效,因为他是直接对内存进行拷贝,数据对象的内容就全部都有了,不需要重新创建内存区域重新实例化赋值这些操作了,这样的话速度能够快很多。
  • 隐藏制造新实例的复杂性
  • 重复地创建相似对象时可以考虑使用原型模式

缺点:

  • 每一个类必须配备一个克隆方法
  • 深层复制比较复杂

特点:

  • 由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。
  • 目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。
  • 根据对象克隆深度层次的不同,有浅度克隆与深度克隆。

适用场合:

  • 复制对象的结构与数据
  • 希望对目标对象的修改不影响既有的原型对象
  • 创建对象成本较大的情况下
  • 在创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据。
  • 希望对目标对象的修改不影响既有的原型对象(深度克隆的时候可以完全互不影响)
  • 隐藏克隆操作的细节。很多时候,对对象本身的克隆需要涉及到类本身的数据细节。

使用时注意事项:

  • 使用原型模式复制对象不会调用类的构造方法。所以,单例模式与原型模式是冲突的,在使用时要特别注意。
  • Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

2. 具体实例:

银行的电子账单、广告信需要你群发邮件,特点:量大、时间要求紧。

想一下这个怎么实现,其实简单的想法就是邮件类,邮件模板类,发送邮件类这样三个函数,然后使用多线程给每个线程分配一个邮件的对象进行发送。这样的话的缺点就是需要实例化很多的对象,实例化对象的时候会有类的初始化赋值这一类的操作,速度慢,然后我们想就是因为每一封邮件是类似的,只是发送的人姓名什么的不同,我们直接拷贝对象,直接从内存中拷贝对象的话对象的信息都有然后重新进行修改,省下了new的整个过程,速度快很多。

设计的类图:

2

其实从图中看不出具体的原型模式是怎么回事。看一下具体的代码;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class EventTemplate {
private String eventSubject, eventContent;

public EventTemplate(String eventSubject, String eventContent) {
this.eventSubject = eventSubject;
this.eventContent = eventContent;
}

public String geteventSubject() {
return eventSubject;
}

public String geteventContent() {
return eventContent;
}
}
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
54
55
56
57
public class Mail implements Cloneable {
private String receiver;
private String subject;
private String content;
private String tail;
private ArrayList<String> ars;
public Mail(EventTemplate et) {
this.tail = et.geteventContent();
this.subject = et.geteventSubject();

}

@Override
public Mail clone() {
Mail mail = null;
try {
mail = (Mail) super.clone();
mail.ars = (ArrayList<String>)this.ars.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return mail;
}

public String getReceiver() {
return receiver;
}

public void setReceiver(String receiver) {
this.receiver = receiver;
}

public String getSubject() {
return subject;
}

public void setSubject(String subject) {
this.subject = subject;
}

public void setContent(String content) {
this.content = content;
}

public String getContent() {
return content;
}

public String getTail() {
return tail;
}

public void setTail(String tail) {
this.tail = tail;
}
}

Mail这个类实现了Cloneable,继承了public Mail clone() {}这个方法,用来实现对象的拷贝。

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
public class MainTest {
public static void main(String[] args) {
int i = 0;
int MAX_COUNT = 10;
EventTemplate et = new EventTemplate("9月份信用卡账单", "国庆抽奖活动...");

Mail mail = new Mail(et);

while (i < MAX_COUNT) {
// 以下是每封邮件不同的地方
Mail cloneMail = mail.clone();
cloneMail.setContent(getRandString(5) + ",先生(女士):你的信用卡账单..."
+ mail.getTail());
cloneMail.setReceiver(getRandString(5) + "@" + getRandString(8)
+ ".com");
// 然后发送邮件
sendMail(cloneMail);
i++;
}

}

public static String getRandString(int maxLength) {
String source = "abcdefghijklmnopqrskuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuffer sb = new StringBuffer();
Random rand = new Random();
for (int i = 0; i < maxLength; i++) {
sb.append(source.charAt(rand.nextInt(source.length())));
}
return sb.toString();
}

public static void sendMail(Mail mail) {
System.out.println("标题:" + mail.getSubject() + "\t收件人:"
+ mail.getReceiver() + "\t内容:" + mail.getContent()
+ "\t....发送成功!");
}
}

在测试类中每次发不同的邮件时都会Mail cloneMail = mail.clone();就是对象的复制。

本文标题:设计模式之原型模式

文章作者:WilsonSong

发布时间:2018年10月18日 - 14:10

最后更新:2018年10月18日 - 14:10

原始链接:https://songwell1024.github.io/2018/10/18/PrototypePattern/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------本文结束感谢您的阅读-------------