Fork me on GitHub

原型模式与保护性拷贝

原型模式可以理解为直接从已存在的对象中拷贝出一个新对象,在重新创建一个对象消耗较大,但又需要用到两个相互不影响的对象的时候才用到,这是它与单例模式的区别所在

原型模式中拷贝的方法有浅拷贝和深拷贝两种,浅拷贝因为直接引用对象,所以在修改拷贝出的对象的时候可能会影响到原对象,下面用购物商城的用户举个简单的例子

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
public class User{
public User(){
}
private String name;
private Image icon;
private ArrayList<String> address = new ArrayList<>();

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Image getIcon() {
return icon;
}

public void setIcon(Image icon) {
this.icon = icon;
}

public ArrayList<String> getAddress() {
return address;
}

public void setAddress(ArrayList<String> address) {
this.address = address;
}
}

浅拷贝

用户有用户名、头像、多个地址,如果要进行拷贝的话应该继承Cloneable接口并重写clone()函数,下面是浅拷贝的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
protected User clone() {
try {
User user = (User)super.clone();
user.icon = this.icon;
user.name = this.name;
user.address = this.address;
return user;
} catch (CloneNotSupportedException e){

}
return null;
}

为什么称它为浅拷贝呢?因为在User类中我们使用的是引用型字段,即ArrayList,如果我们对拷贝对象的ArrayList中的对象进行修改,原对象也会受到影响,和拷贝对象中的地址保持一致,所以我们应该使用深拷贝,对引用型字段也进行拷贝,而不是简单地赋值

深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
protected User clone() {
try {
User user = (User)super.clone();
user.icon = this.icon;
user.name = this.name;
user.address = (ArrayList<String>) this.address.clone(); //对引用型字段进行拷贝
return user;
} catch (CloneNotSupportedException e){

}
return null;
}

完整代码如下:

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
public class User implements Cloneable{
public User(){
}
private String name;
private Image icon;
private ArrayList<String> address = new ArrayList<>();

@Override
protected User clone() {
try {
User user = (User)super.clone();
user.icon = this.icon;
user.name = this.name;
user.address = (ArrayList<String>) this.address.clone();
return user;
} catch (CloneNotSupportedException e){

}
return null;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Image getIcon() {
return icon;
}

public void setIcon(Image icon) {
this.icon = icon;
}

public ArrayList<String> getAddress() {
return address;
}

public void setAddress(ArrayList<String> address) {
this.address = address;
}
}

保护性拷贝

保护性拷贝其实就是原型模式的一个实际应用,比如说上面举的商城的例子,如果我们在其他需要用到User对象的场景下不小心修改了User对象,那将使服务端和客户端的信息不一致,所以在这个场景下十分适合使用原型模式