原型模式

简介:

定义

通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。这是原型模式的用意。

原型模式的结果有两种,一种是浅复制,一种是深复制。

浅复制

用Java方式实现浅复制,被复制对象必须实现Cloneable接口。

package com.faith.net.prototype.simple;

import java.util.List;

/**
 * 简历类
 */
public class Resume implements Cloneable {

    private String name;
    private Integer age;
    private List<String> blogs;

    public Resume() {    }

    public Resume(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    ···省略getter、setter

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

测试:


package com.faith.net.prototype.simple;

import java.util.ArrayList;
import java.util.List;

/**
 * 测试类
 */
public class CloneTest {

    public static void main(String[] args) throws Exception {

        Resume resume = new Resume("faith", 28);
        List<String> blogs = new ArrayList<String>(2);
        blogs.add("yunqi");
        resume.setBlogs(blogs);

        Resume clone = (Resume) resume.clone();

        System.out.println(clone.getName() + ": " + clone.getAge()); // faith: 28
        System.out.println(clone.getBlogs().get(0)); // yunqi

        blogs.set(0, "csdn");
        System.out.println(clone.getBlogs().get(0)); // csdn
    }
}

修改resume对象的blogs属性,却使得clone对象的blogs属性也同时改变了,能够看出这里是浅复制,对于引用对象类型的成员,只是复制了引用地址,而没有重新生成新的拷贝对象。

深复制

实现深复制就要将深复制的逻辑写到clone方法中,如下:

package com.faith.net.prototype.simple;

import java.io.*;
import java.util.List;

/**
 * 简历类
 */
public class Resume implements Cloneable, Serializable {

    private String name;
    private Integer age;
    private List<String> blogs;

    public Resume() {    }

    public Resume(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    ···省略getter、setter

    @Override
    protected Object clone() {
        try{
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);

            Resume clone = (Resume)ois.readObject();
            clone.age = this.age + 1;

            return clone;
        }catch (Exception e){
            throw new RuntimeException();
        }
    }
}

测试类:

/**
 * 测试类
 */
public class CloneTest {

    public static void main(String[] args) throws Exception {

        Resume resume = new Resume("faith", 28);
        List<String> blogs = new ArrayList<String>(2);
        blogs.add("yunqi");
        resume.setBlogs(blogs);

        Resume clone = (Resume) resume.clone();

        System.out.println(clone.getName() + ": " + clone.getAge()); // faith: 29
        System.out.println(clone.getBlogs().get(0)); // yunqi

        blogs.set(0, "csdn");
        System.out.println(clone.getBlogs().get(0)); // yunqi
    }
}

值得注意的是,这里的clone方法中的逻辑可以通过多种方式实现,只要能重新创建引用类型对象即可,反序列化方式能够重新创建List类型对象,所以这里能够应用。
还可以使用反射方式,Spring中大量使用了反射实现深复制;或者直接将原对象中的blogs取出,循环遍历元素并添加到新的List对象中。

Spring中的原型模式

Spring中的原型模式大都是使用反射实现的。这里讲一下应用场景:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" scope="singleton"/>

这里的scope是用来配置spring bean的作用域,默认为singleton,Spring IOC容器中只会存在一个共享的bean实例,所有对bean的请求只会返回同一实例。

当scope值为prototype,即为原型模式的应用,每一次请求(将其注入到另一个bean,或以程序方式调用容器的getBean()方法)都会产生一个新的bean实例,相当于new操作。

容器在装配完prototype实例后交给客户端,随后就对该prototype实例不闻不问。而清除prototype对象并释放其所持有的资源,都是客户端代码的职责。

目录
相关文章
|
10天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1216 5
|
9天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1180 87
|
10天前
|
云栖大会
阿里云云栖大会2025年9月24日开启,免费申请大会门票,速度领取~
2025云栖大会将于9月24-26日举行,官网免费预约畅享票,审核后短信通知,持证件入场
1773 12
|
19天前
|
人工智能 运维 安全
|
2天前
|
资源调度
除了nrm-pm,还有哪些工具可以管理多个包管理器的源?
除了nrm-pm,还有哪些工具可以管理多个包管理器的源?
230 127
|
10天前
|
弹性计算 Kubernetes jenkins
如何在 ECS/EKS 集群中有效使用 Jenkins
本文探讨了如何将 Jenkins 与 AWS ECS 和 EKS 集群集成,以构建高效、灵活且具备自动扩缩容能力的 CI/CD 流水线,提升软件交付效率并优化资源成本。
362 0