搜索
写经验 领红包
 > 社会

原型模式结构图(原型模式例子)

导语:架构模式----原型模式

原型模式结构图(原型模式例子)

原型模式(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、在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在许多嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来比较麻烦。

本文内容由小面整理编辑!