定义:
prototype pattern是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。是一种创建模式。
角色
-
Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。
-
ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
-
Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。由于客户类针对抽象原型类Prototype编程,因此用户可以根据需要选择具体原型类,系统具有较好的可扩展性,增加或更换具体原型类都很方便。
适用场景:
- 资源优化场景---类初始化消耗太多资源,这个资源包括数据、硬件资源等
- 构造函数比较复杂
- JAVA创建类实例基本上是适用new关键字。有时候需要使用 “在不指定类名的前提下生成实例”的需求。
- 对象种类繁多,无法将他们整合到一个类中
- 难以根据类生成实例,
- 解耦框架和生成的实例
- 性能和安全要求的场景--通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象多个修改者的场景---一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与Java融为浑然一体,大家可以随手拿来使用。
缺点
1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
2、实现原型模式每个派生类都必须实现 Clone接口。
3、逃避构造函数的约束。
一旦在类中使用到了别的类名,就不能和该类分离,也无法实现复用。也就意味着两者是耦合在一起的。
日常框架中的prototype有:Spring中,原型模式应用的非常广泛,scope='prototype',还有JSON.parseObject()也是原型模式。
原型模式的核心就是克隆方法
java的Object类的clone方法和java.lang.cloneable接口:clone方法是浅拷贝
浅克隆:
-
在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。
-
简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
-
在Java语言中,通过覆盖Object类的clone()方法可以实现浅克隆。
深克隆:
-
在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。
-
简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。
-
在Java语言中,如果需要实现深克隆,可以通过序列化(Serialization)等方式来实现。需要注意的是能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。