创建型-原型模式
# 什么是原型模式
- 如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式,来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式,简称原型模式。
- 一般用于一个对象的属性已经确定,需要产生很多相同对象的时候使用。
- Java 中自带 clone() 方法
- 一个类想实现深克隆功能
- 实现标记型接口 Cloneable
- 重写 clone() 方法
# 为什么使用原型模式
- 可以降低一些对象的创建成本,这个创建成本主要体现在一些属性值是经过复杂的计算得到,或者从 RPC、网络、数据库、文档系统等非常慢速的 IO 中读取。
# 深拷贝和浅拷贝的区别
浅拷贝:仅赋值对象属性这一级,如果对象的属性还有引用,那么拷贝前后两者所指的对象地址相同。
深拷贝:就是完完整整拷贝一个对象,包含对象内部的对象引用。
解决深拷贝的方法
递归拷贝对象、对象的引用对象以及引用对象的引用对象……直到要拷贝的对象只包含基本数据类型数据,没有引用对象为止。
先将对象序列化,然后再反序列化成新的对象。
public Object deepCopy(Object object) { ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(object); ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return oi.readObject(); }
1
2
3
4
5
6
7
8
9
# 浅拷贝实现
/**
* 浅拷贝
*
* @author Thomas Yang
* @version 1.0
* @date 2020/8/30 4:18 PM
*/
public class ShallowCope {
@SneakyThrows
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = (Person) person1.clone();
System.out.println(person2.age + " " + person2.score);
System.out.println(person2.location);
System.out.println(person1.location == person2.location);
person1.location.street = "hz";
System.out.println(person2.location);
}
}
class Person implements Cloneable {
int age = 9;
int score = 100;
Location location = new Location("bj", 22);
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Location {
String street;
int roomNo;
public Location(String street, int roomNo) {
this.street = street;
this.roomNo = roomNo;
}
@Override
public String toString() {
return "Location{" +
"street='" + street + '\'' +
", roomNo=" + roomNo +
'}';
}
}
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
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
# 深拷贝实现
/**
* 浅拷贝
*
* @author Thomas Yang
* @version 1.0
* @date 2020/8/30 4:18 PM
*/
public class DeepCope {
@SneakyThrows
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = (Person) person1.clone();
System.out.println(person2.age + " " + person2.score);
System.out.println(person2.location);
System.out.println(person1.location == person2.location);
person1.location.street = "hz";
System.out.println(person1.location);
System.out.println(person2.location);
}
}
class Person implements Cloneable {
int age = 9;
int score = 100;
Location location = new Location("bj", 22);
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.location = (Location) location.clone();
return person;
}
}
class Location implements Cloneable {
String street;
int roomNo;
public Location(String street, int roomNo) {
this.street = street;
this.roomNo = roomNo;
}
@Override
public String toString() {
return "Location{" +
"street='" + street + '\'' +
", roomNo=" + roomNo +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
# 深、浅拷贝时,是否需要特殊处理 String 类型?
- 不需要,虽然浅拷贝后,前后两个对象的属性同时指向一个 String 地址引用
- 但是 String 底层实现是静态数组实现,本身是不可变的,如果其中一个对象对其属性修改,并不会修改原先 String 值,只会指向新生成的 String 地址。
- 故 String 类型的不需要特殊处理,但是如果使用 StringBuilder 那就不同了,这个指的是同一个对象,道理同上需要深拷贝,也就是需要实现 Cloneable 接口,实现 clone 方法。
上次更新: 2020/09/08, 15:09:00