原型模式
原型模式算是JAVA中最简单的设计模式了,原因是因为它已经被提供了语言级的支持,但是如果提到它的实现原理,又是最复杂的一个设计模式。
(1)先看一下原型模式的UML类图
其中,Prototype是一个原型的抽象类或借口,它里面有一个共有方法,叫clone。ConcretePrototype1与ConcretePrototype2是两个具体的实例,继承或实现了Prototype。这就对应了定义中用原型实例指定创建对象的种类。Client是客户端类,它与Prototype是关联的关系,即在Client类的实例中,有Prototype的对象。客户端可以通过调用Prototype的clone方法来对实现了Prototype的ConcretePrototype1或ConcretePrototype2的对象进行复制来创建新对象,这样比new会有更高的执行效率。
(2)下面我们先来看看这个又简单又复杂的设计模式的定义
定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
定义比较简单,总结一下是通过实例指定种类,通过拷贝创建对象。
在JAVA语言中使用原型模式是非常简单的,这是因为Object类当中提供了一个本地方法clone,而JAVA中的任何类只要实现了Cloneable标识接口,就可以使用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 59 60 61 62 63 64 65 66 67 | public class Prototype implements Cloneable { private int x; private int y; private int z; public Prototype() { this .x = 2 ; this .y = 3 ; this .z = 4 ; } public void change() { this .x = 9 ; this .y = 8 ; this .z = 7 ; } public Prototype clone() { Object object = null ; try { object = super .clone(); } catch (CloneNotSupportedException exception) { throw new RuntimeException(exception); } return (Prototype) object; } public String toString() { return "[" + x + "," + y + "," + z + "]" ; } public static void main(String[] args) { Prototype prototype1 = new Prototype(); prototype1.change(); System.out.println(prototype1); Prototype prototype2 = prototype1.clone(); System.out.println(prototype2); } } |
输出结果:
[9,8,7]
[9,8,7]
从输出结果可以看出来,clone方法将prototype1复制了一个,然后赋给了prototype2,这就像复制粘贴一样。值得注意的是,在使用Object.clone()方法去拷贝一个对象时,构造方法是不被执行的,否则prototype2实例中x,y,z的值应该为2,3,4才对,如果你觉得不够直观,可以在构造方法里写一个输出语句试试。
(3)从原型模式的使用方式不难推断出,原型模式常使用于以下场景:
1、对象的创建非常复杂,可以使用原型模式快捷的创建对象。
2、在运行过程中不知道对象的具体类型,可使用原型模式创建一个相同类型的对象,或者在运行过程中动态的获取到一个对象的状态。
对于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 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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | class Field implements Cloneable{ private int a; public int getA() { return a; } public void setA( int a) { this .a = a; } protected Field clone() { Object object = null ; try { object = super .clone(); } catch (CloneNotSupportedException exception) { throw new RuntimeException(exception); } return (Field) object; } } public class DeepPrototype implements Cloneable { private int x; private int y; private int z; private Field field; public DeepPrototype() { this .x = 2 ; this .y = 3 ; this .z = 4 ; this .field = new Field(); this .field.setA( 5 ); } public Field getField() { return field; } protected DeepPrototype clone() { Object object = null ; try { object = super .clone(); ((DeepPrototype)object).field = this .field.clone(); } catch (CloneNotSupportedException exception) { throw new RuntimeException(exception); } return (DeepPrototype) object; } public String toString() { return "[" + x + "," + y + "," + z + "," + field.getA() + "]" ; } public static void main(String[] args) { DeepPrototype prototype1 = new DeepPrototype(); System.out.println(prototype1); System.out.println(prototype1.getField()); DeepPrototype prototype2 = prototype1.clone(); System.out.println(prototype2); System.out.println(prototype2.getField()); } } |
输出结果:
[2,3,4,5]
com.prototype.Field@a90653
[2,3,4,5]
com.prototype.Field@de6ced
(4)下面我们来看下原型模式的主要优点:
1、由于clone方法是由虚拟机直接复制内存块执行,所以在速度上比使用new的方式创建对象要快。
2、可以基于原型,快速的创建一个对象,而无需知道创建的细节。
3、可以在运行时动态的获取对象的类型以及状态,从而创建一个对象。
然而原型模式的缺点也是相当明显的,主要的缺点就是实现深度拷贝比较困难,需要很多额外的代码量。
不过实际当中我们使用原型模式时,也可以写一个基类实现Cloneable接口重写clone方法,然后让需要具有拷贝功能的子类继承自该类,这是一种节省代码量的常用方式。像上面的例子一样,如果一个类继承自Prototype,则会自动具有拷贝功能。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架