设计模式之原型模式

模式定义

用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。

模式使用场景

  1. 类初始化需要消耗非常多的资源,这个资源包括数据,硬件资源等,通过原型拷贝避免这些消耗。
  2. 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
  3. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。

UML图

Alt text

角色描述

* Client: 客户端用户
* Prototype:抽象类或接口,声明具备clone能力
* ConcretePrototype:具体的原型类

实现

文档拷贝为例。

Prototype抽象类为java.lang.clone,ConcretePrototype通过重写该方法完成对象的拷贝功能。

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
58
59
60
package prototype;
import java.util.ArrayList;
/**
* Created by cdx0312
* 2018/3/25
*/
public class ConcretePrototype implements Cloneable{
private String mText;
private ArrayList<String> mImages = new ArrayList<>();
public ConcretePrototype() {
System.out.println("concretePrototype构造函数");
}
@Override
protected Object clone() throws CloneNotSupportedException {
try {
ConcretePrototype concretePrototype = (ConcretePrototype) super.clone();
concretePrototype.mText = this.mText;
concretePrototype.mImages = this.mImages;
return concretePrototype;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String getmText() {
return mText;
}
public void setmText(String mText) {
this.mText = mText;
}
public ArrayList<String> getmImages() {
return mImages;
}
public void setmImages(ArrayList<String> mImages) {
this.mImages = mImages;
}
public void addImage(String img) {
this.mImages.add(img);
}
public void showContent() {
System.out.println("==========start===========");
System.out.println("Text: " + mText);
System.out.println("Images List: ");
for (String string : mImages) {
System.out.println("image name : " + string);
}
System.out.println("============end==========");
}
}

Client:

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
package prototype;
/**
* Created by cdx0312
* 2018/3/25
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
//创建对象
ConcretePrototype original = new ConcretePrototype();
original.setmText("first");
original.addImage("pic 1");
original.addImage("pic 2");
original.addImage("pic 3");
original.addImage("pic 4");
original.showContent();
//复制对象
ConcretePrototype clone = (ConcretePrototype) original.clone();
clone.showContent();
//修改并展示复制的对象
clone.setmText("clone");
clone.showContent();
//展示原型对象
original.showContent();
}
}

结果:修改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
concretePrototype构造函数
==========start===========
Text: first
Images List:
image name : pic 1
image name : pic 2
image name : pic 3
image name : pic 4
============end==========
==========start===========
Text: first
Images List:
image name : pic 1
image name : pic 2
image name : pic 3
image name : pic 4
============end==========
==========start===========
Text: clone
Images List:
image name : pic 1
image name : pic 2
image name : pic 3
image name : pic 4
============end==========
==========start===========
Text: first
Images List:
image name : pic 1
image name : pic 2
image name : pic 3
image name : pic 4
============end==========

深浅拷贝的区别:引用类型拷贝过程中,只拷贝了其引用,并没有将对象进行复制:

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
package prototype;
/**
* Created by cdx0312
* 2018/3/25
*/
public class Client1 {
public static void main(String[] args) throws CloneNotSupportedException {
//创建对象
ConcretePrototype original = new ConcretePrototype();
original.setmText("first");
original.addImage("pic 1");
original.addImage("pic 2");
original.addImage("pic 3");
original.addImage("pic 4");
original.showContent();
ConcretePrototype clone = (ConcretePrototype) original.clone();
clone.showContent();
clone.setmText("clone1");
clone.addImage("new pic 5");
clone.showContent();
original.showContent();
}
}
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
concretePrototype构造函数
==========start===========
Text: first
Images List:
image name : pic 1
image name : pic 2
image name : pic 3
image name : pic 4
============end==========
==========start===========
Text: first
Images List:
image name : pic 1
image name : pic 2
image name : pic 3
image name : pic 4
============end==========
==========start===========
Text: clone1
Images List:
image name : pic 1
image name : pic 2
image name : pic 3
image name : pic 4
image name : new pic 5
============end==========
==========start===========
Text: first
Images List:
image name : pic 1
image name : pic 2
image name : pic 3
image name : pic 4
image name : new pic 5
============end==========

深拷贝过程中需要将引用类型的字段也要进行拷贝,而不是单纯的拷贝引用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 深拷贝
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
try {
ConcretePrototype concretePrototype = (ConcretePrototype) super.clone();
concretePrototype.mText = this.mText;
concretePrototype.mImages = (ArrayList<String>) this.mImages.clone();
return concretePrototype;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

优点和缺点

  • 优点:原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是需要在一个循环体中产生大量对象时。

  • 缺点:直接在内存中拷贝,构造方法不会执行,减少了约束,需要注意。

Donate comment here