原型模式结构图(原型模式例子)
导语:架构模式----原型模式
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,属于创建型模式。
原型模式的核心在于拷贝原型对象。以系统中已存在的一个对象为原型,直接基于内存二进制流进行拷贝,无需再经历耗时的对象初始化过程(不调用构造函数),性能提升许多。当对象的构建过程比较耗时时,可以利用当前系统中已存在的对象作为原型,对其进行克隆(一般是基于二进制流的复制)。躲避初始化过程,使得新对象的创建时间大大减少。
原型模式主要包含三个角色:
客户(client):客户类提出创建对象的请求
抽象原型(prototype):规定拷贝接口
具体原型(concrete prototype):被拷贝的对象
注:对不通过new关键字,而是通过对象拷贝来实现创建对象的模式就称作原型模式
对于以上代码,纯属体力工作。以上这个代码就是原型模式的需求场景;那原型模式,能帮助我们解决这样的问题;
原型模式主要适用于一下场景:
1、类初始化消耗资源较多。
2、new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
3、构造函数比较复杂。
4、循环体中生产大量对象时。
在spring中,原型模式应用的非常广泛。例如 scope=&34; ,在我们经常用的JSON.parseObject()也是一种原型模式。
原型模式的通用写法
一个标准的原型模式代码,应该是这样设计的。先创建原型IPrototype接口:
创建具体需要克隆的对象 ConcretePrototype
测试代码:
运行结果:
原型模式就是这么简单,在这个简单的场景之下,看上去操作好像复杂了。但如果有几百个属性需要复制,我们就可以一劳永逸。但是,上面的复制过程是我们自己完成的,在实际编码中,我们一般不会浪费这样的体力劳动,JDK已经帮我们实现了一个现成的API,我们只需要实现Cloneable接口即可。修改ConcretePrototype类:
重新运行,也会是同样的结果。有了JDK的支持再多的属性复制我们也能轻而易举的搞定。下面新增一个个人爱好的属性hobbies:
修改测试代码:
运行结果:
我们给复制后的克隆对象新增了一项爱好,发现原型对象也发生了变化,这显然不是我们想要的结果。因为我们希望克隆出来的对象应该和原型对象时两个独立的对象,不应该再有关系。从测试结果来看,hobbies公用了一个内存地址,意味着复制的不是值,而是引用的地址。这样的话如果我们修改任意一个对象的属性值,两个对象的hobbies值都会改变。这就是我们常常说的额浅克隆。知识完整复制了值类型的数据,没有赋值引用对象。换言之,所有的引用对象仍然指向原来的对象,显然不是我们想要的结果。下面我们来看深度克隆代码改造。
使用序列化实现深度克隆
在上面的基础上,我们增加一个deepClone()方法:
修改测试代码:
运行程序,得到了我们想要的结果:
克隆破坏单例模式
如果我们克隆的目标对象时单例对象,那意味着,深克隆就会破坏单例。实际上防止克隆破坏单例解决思路非常简单,禁止深度克隆即可。要么单例类不实现Cloneable接口;要么我们重写clone()方法,在clone()方法中返回单例对象即可。
原型模式的优缺点:
优点:
1、性能优良,java自带的原型模式是基于内存二进制流的拷贝,比直接new一个对象性能上提升了许多。
2、可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,简化了创建对象的过程;
缺点:
1、需要为每一个类配置一个克隆方法。
2、克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了开闭原则。
3、在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在许多嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来比较麻烦。
本文内容由小面整理编辑!