原型模式

“你是我,我是你,我是我,你是你。”

这里说的原型模式,指的是对目标对象进行深拷贝,本文采用Java自带的克隆机制来实现。

目标类

首先声明个接口:

1
interface Fruitprototype extends Cloneable{}

要使用Java自带的克隆机制,必须实现Cloneable这个标记接口。

接着写一个实现类(实例该类就将得到一个要拷贝的目标对象):

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
class FruitImpl implements Fruitprototype {
private String name;
private Orangeprototype orange;
public FruitImpl(String name, Orangeprototype orange) {
this.name = name;
this.orange = orange;
}
public FruitImpl getClone() {
FruitImpl fruit = null;
try {
fruit = (FruitImpl)super.clone();
// 对内部引用对象进行拷贝操作
fruit.orange = this.getOrange().getClone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return fruit;
}
public Orangeprototype getOrange() {
return orange;
}
}

关键的代码在getClone()中,注释下的语句不能省略,因为clone()本身是浅拷贝,如果orange内也存在引用,则逐级调用。

引用类

代码如下:

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
class Orangeprototype implements Cloneable {
private String name;
private int id;
public Orangeprototype(String name, int id) {
this.name = name;
this.id = id;
}
public Orangeprototype getClone() {
Orangeprototype orange = null;
try {
orange = (Orangeprototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return orange;
}
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
}

思路和目标类的实现相同。

测试用例

1
2
3
4
5
6
7
8
public static void main(String[] args) {
Orangeprototype orange01 = new Orangeprototype("orange01", 1);
Fruitprototype fruit01 = new FruitImpl("fruit01", orange01);
Fruitprototype fruit02 = ((FruitImpl) fruit01).getClone();
((FruitImpl) fruit02).getOrange().setId(02);
((FruitImpl) fruit02).getOrange().setName("orange02");
System.out.println(orange01.getId() + " " + orange01.getName());
}

拷贝一份fruit01指向的对象并声明为fruit02,调用fruit02的方法来更改内部字段原本的内容,在这里将内部指向的Orangeprototype对象的id改为了02,name改为了orange02。打印原目标对象内指向的Orangeprototype对象的id和name,仍然是1和orange01,如果将FruitImpl类中注释下的语句删除,则打印的结果是2和orange02。