设计模式15-Prototype

本文最后更新于:3 years ago

原型模式

  原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于 创建型模式 ,它提供了一种创建对象的最佳方式。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

如果想了解原型模式的具体的介绍,菜鸟教程介绍得比较详细↓
菜鸟教程-原型模式

结构图


优缺点

优点:

1、性能提高。
2、逃避构造函数的约束。

缺点:

1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
2、必须实现 Cloneable 接口。

使用场景

1、资源优化场景。
2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
3、性能和安全要求的场景。

实现代码

原型模式在真正的工作中可以说是很难用到的,但是还是需要来介绍的,作为了解即可

原型模式也可以被称为是克隆模式,因为原理其实就是一种克隆。是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式

首先我们创建一个自定义类型Appearance(height、weight两个属性),用于记录一个物体的外表
接着创建一个抽象类(Object_),实现Cloneable接口,并且重写父类Object中的clone方法
最后创建实体类Animal继承Object_类

Code:

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Animal animal1 = new Animal();
animal1.setAppearance(new Appearance(100, 200));
animal1.setColor("black");

Animal animal2 = (Animal) animal1.clone();
System.out.println("animal1 --> " + animal1.color + " " + animal1.appearance);
System.out.println("animal2 --> " + animal2.color + " " + animal2.appearance);
}
}

public class Appearance {
int height;
int weight;

public int getHeight() {
return height;
}

public void setHeight(int height) {
this.height = height;
}

public int getWeight() {
return weight;
}

public void setWeight(int weight) {
this.weight = weight;
}

public Appearance(int height, int weight) {
this.height = height;
this.weight = weight;
}

@Override
public String toString() {
return "Appearance{" +
"height=" + height +
", weight=" + weight +
'}';
}
}

public abstract class Object_ implements Cloneable{
Appearance appearance;
String color;

public Appearance getAppearance() {
return appearance;
}

public void setAppearance(Appearance appearance) {
this.appearance = appearance;
}

public String getColor() {
return color;
}

public void setColor(String color) {
this.color = color;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

@Override
public String toString() {
return "Object_{" +
"appearance=" + appearance +
", color='" + color + '\'' +
'}';
}
}

public class Animal extends Object_{
public Animal(){
System.out.println("Animal...");
}
}

输出结果:

1
2
3
Animal...
animal1 --> black Appearance{height=100, weight=200}
animal2 --> black Appearance{height=100, weight=200}

可以发现两个animal实例的结果是一样的

再说一下Object_中有关clone方法

1
2
3
4
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

这里的克隆是重写了父类Object的方法,然后调用Object中的实现的clone方法。

但为什么要重写这个方法呢?如果你查看Object源码的话会发现Object中的clone方法是protect的,只能够子类使用,
所以这里我们需要重写来改变它的访问权限

在Main方法中我们调用了Animal的父类Object_来实现创建重复对象(Animal),实现克隆

以上就是原型模式的代码

接着我们再多说一些有关这个模式的知识,简单了解即可

我们改变一下Mian函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Animal animal1 = new Animal();
animal1.setAppearance(new Appearance(100, 200));
animal1.setColor("black");

Animal animal2 = (Animal) animal1.clone();
System.out.println("animal1 --> " + animal1.color + " " + animal1.appearance);
System.out.println("animal2 --> " + animal2.color + " " + animal2.appearance);

System.out.println(animal1.appearance == animal2.appearance);
animal1.appearance.height = 150;
System.out.println(animal2.appearance);
}
}

我们在Main函数中对比animal1和animal2中引用类型 appearance 的值是否相同,并且将animal1中的height改变,观察animal2中height的值

输出结果:

1
2
3
4
5
Animal...
animal1 --> black Appearance{height=100, weight=200}
animal2 --> black Appearance{height=100, weight=200}
true
Appearance{height=150, weight=200}

可以发现animal1中的 appearance 和animal2中的 appearance 是一样的,其实也就是二者引用了同一对象,这就是浅克隆
当改变引用对象中的值时,animal1和animal2都发生了改变

在浅克隆中,克隆出来的基本类型是复制到新的实例中的,但是对于引用类型,是将引用类型的地址赋值给新的实例的

如果我们不想要将而这指向同一个对象时,这个时候就涉及到深克隆了

我们先将深克隆的代码贴出来

Code:

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Animal animal1 = new Animal();
animal1.setAppearance(new Appearance(100, 200));
animal1.setColor("black");

Animal animal2 = (Animal) animal1.clone();
System.out.println("animal1 --> " + animal1.color + " " + animal1.appearance);
System.out.println("animal2 --> " + animal2.color + " " + animal2.appearance);

System.out.println(animal1.appearance == animal2.appearance);
animal1.appearance.height = 150;
System.out.println(animal2.appearance);
}
}

public class Appearance implements Cloneable{
int height;
int weight;

public int getHeight() {
return height;
}

public void setHeight(int height) {
this.height = height;
}

public int getWeight() {
return weight;
}

public void setWeight(int weight) {
this.weight = weight;
}

public Appearance(int height, int weight) {
this.height = height;
this.weight = weight;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

@Override
public String toString() {
return "Appearance{" +
"height=" + height +
", weight=" + weight +
'}';
}
}

public abstract class Object_ implements Cloneable{
Appearance appearance;
String color;

public Appearance getAppearance() {
return appearance;
}

public void setAppearance(Appearance appearance) {
this.appearance = appearance;
}

public String getColor() {
return color;
}

public void setColor(String color) {
this.color = color;
}

@Override
protected Object clone() throws CloneNotSupportedException {
Object_ object = (Object_) super.clone();
object.appearance = (Appearance)appearance.clone();
return object;
}

@Override
public String toString() {
return "Object_{" +
"appearance=" + appearance +
", color='" + color + '\'' +
'}';
}
}

public class Animal extends Object_ {
public Animal(){
System.out.println("Animal...");
}
}

输出结果

1
2
3
4
5
Animal...
animal1 --> black Appearance{height=100, weight=200}
animal2 --> black Appearance{height=100, weight=200}
false
Appearance{height=100, weight=200}

可以发现animal1中的 appearance 和animal2中的 appearance 指向的并不是同一个对象了
改变animal1中的appearance,并不会影响animal2中appearance的值

分析一下代码:

1
public class Appearance implements Cloneable{}

我们将Appearance类直接实现了Cloneable接口

1
2
3
4
5
6
@Override
protected Object clone() throws CloneNotSupportedException {
Object_ object = (Object_) super.clone();
object.appearance = (Appearance)appearance.clone();
return object;
}

并且将Object_类中的clone方法进行了修改,我们先克隆出来一个Object_类,然后将这个类中的appearance变量指向一个Object_类中appearance克隆出来的Appearance类,有点绕,但是看代码还是很好理解的。这就是深克隆,不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。

补充的部分作为了解即可,开发过程中基本上是使用不到原型模式的。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!