原型设计模式

原型设计模式

原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。

原型模式的优点:

Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。

可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

原型模式的缺点:

需要为每一个类都配置一个 clone 方法

clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。

当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。

模式的结构

原型模式包含以下主要角色。

抽象原型类:规定了具体原型对象必须实现的接口。

具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。

访问类:使用具体原型类中的 clone() 方法来复制新的对象。

原型模式的克隆分为浅克隆和深克隆。

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址(基本类型各自的,引用类型公共的)。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

浅克隆实现

下面是浅克隆的实现步骤,深克隆需要重写Clone()

对象的类实现Cloneable接口;

覆盖Object类的clone()方法(覆盖clone()方法,访问修饰符设为public,默认是protected,但是如果所有类都在同一个包下protected是可以访问的);

实例:

定义Clone接口

public abstract class Prototype implements Cloneable{

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

真实类

public class RealizeType extends Prototype{
    private String name;
    private String value;

    public RealizeType(String name, String value) {
        this.name = name;
        this.value = value;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "RealizeType{" +
                "name='" + name + '\'' +
                ", value='" + value + '\'' +
                '}';
    }
}

测试

public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Prototype prototype = new RealizeType("Jhon", "16");
        RealizeType clone = (RealizeType) prototype.clone();
        clone.setName("Mary");
        System.out.println(prototype);
        System.out.println(clone);
    }
}

输出为:

RealizeType{name='Jhon', value='16'}
RealizeType{name='Mary', value='16'}

能够克隆出不同的对象

深克隆实现

深拷贝实现的是对所有可变(没有被final修饰的引用变量)引用类型的成员变量都开辟内存空间所以一般深拷贝对于浅拷贝来说是比较耗费时间和内存开销的。

方法一:重写Clone()方法

在clone()方法中对应用类型重新new

方法二:序列化实现

通过重写Object的clone方法去实现深克隆十分麻烦,特别是嵌套比较多和有数组的情况下,重写Clone()很复杂。所以我们可以通过序列化实现深克隆。

在Java里深克隆一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。

不推荐大家用Cloneable接口,实现比较麻烦,现在借助Apache Commons或者

springframework可以直接实现:

浅克隆:BeanUtils.cloneBean(Object obj);BeanUtils.copyProperties(S,T);

深克隆:SerializationUtils.clone(T object);

BeanUtils是利用反射原理获得所有类可见的属性和方法,然后复制到target类。

SerializationUtils.clone()就是使用我们的前面讲的序列化实现深克隆,当然你要把要克隆的类实现Serialization接口。

原型模式的应用场景

对象之间相同或相似,即只是个别的几个属性不同的时候。

创建对象成本较大,例如初始化时间长,占用CPU太多,或者占用网络资源太多等,需要优化资源。

创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性。

系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。

在 Spring 中,原型模式应用的非常广泛,例如 scope='prototype'、JSON.parseObject() 等都是原型模式的具体应用。

Spring5中的原型设计模式

原型模式可扩展为带原型管理器的原型模式,它在原型模式的基础上增加了一个原型管理器 PrototypeManager 类。该类用 HashMap 保存多个复制的原型,Client 类可以通过管理器的 get(String id) 方法从中获取复制的原型

在 Spring 中,原型模式应用得非常广泛,例如 scope="prototype" ,我们经常用的 JSON.parseObject() 也是一种原型模式。分为浅克隆和深克隆两种。

SpringFramework 的 IOC 容器中放了很多很多的 Bean ,默认情况下,Bean 的作用域( Scope )是 singleton ,就是单实例的;如果显式声明作用域为 prototype ,那 Bean 的作用域就会变为每次获取都是一个新的,即原型 Bean

pring中,如果一个类被标记为"prototype",每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例。

Spring不能对一个prototype Bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。

相关推荐
黑胡子大叔的小屋21 分钟前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计
ThisIsClark24 分钟前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
雷神乐乐1 小时前
Spring学习(一)——Sping-XML
java·学习·spring
小林coding2 小时前
阿里云 Java 后端一面,什么难度?
java·后端·mysql·spring·阿里云
V+zmm101342 小时前
基于小程序宿舍报修系统的设计与实现ssm+论文源码调试讲解
java·小程序·毕业设计·mvc·ssm
文大。2 小时前
2024年广西职工职业技能大赛-Spring
java·spring·网络安全
一只小小翠2 小时前
EasyExcel 模板+公式填充
java·easyexcel
m0_748256343 小时前
QWebChannel实现与JS的交互
java·javascript·交互
Jelena技术达人3 小时前
Java爬虫获取1688关键字 item_search接口返回值详细解析
java·开发语言·爬虫
u0107735143 小时前
【字符串】-Lc5-最长回文子串(中心扩展法)
java·算法