本文最后更新于: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..."); } }
|
输出结果:
| Animal... animal1 --> black Appearance{height=100, weight=200} animal2 --> black Appearance{height=100, weight=200}
|
可以发现两个animal实例的结果是一样的
再说一下Object_中有关clone方法
| @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
|
这里的克隆是重写了父类Object的方法,然后调用Object中的实现的clone方法。
但为什么要重写这个方法呢?如果你查看Object源码的话会发现Object中的clone方法是protect的,只能够子类使用,
所以这里我们需要重写来改变它的访问权限
在Main方法中我们调用了Animal的父类Object_来实现创建重复对象(Animal),实现克隆
以上就是原型模式的代码
接着我们再多说一些有关这个模式的知识,简单了解即可
我们改变一下Mian函数
| 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的值
输出结果:
| 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..."); } }
|
输出结果
| 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的值
分析一下代码:
| public class Appearance implements Cloneable{}
|
我们将Appearance类直接实现了Cloneable接口
| @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类,有点绕,但是看代码还是很好理解的。这就是深克隆,不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
补充的部分作为了解即可,开发过程中基本上是使用不到原型模式的。