设计模式—创建型模式之原型模式

设计模式---创建型模式之原型模式

原型模式(Prototype Pattern)用于创建重复的对象,同时又能保证性能。

本体给外部提供一个克隆体进行使用。

比如我们做一个SjdwzMybatis,用来操作数据库,从数据库里面查出很多记录,其中很多记录改变很少。每次查数据库,把所有数据都封装一个对象,然后返回。假设有很多线程,来查如下记录:

java 复制代码
Student student = new Student("张三","男");

如果每次都创建对象封装并返回,这样系统就会有很多student;这样就会浪费内存。

Student类如下:

java 复制代码
public class Student {
    private String name;
    private Integer age;

    public Student() {
        System.out.println("创建了Student对象");
    }
    //省略getter() 、 setter() toString()
}

SjdwzMybatis如下:

java 复制代码
public class SjdwzMybatis {

    /**
     * 通过name获取Student
     */
    public Student queryStudent(String name){
        return queryStudentFromDB(name);
    }

    /**
     * 演示从数据库查Student
     */
    private Student queryStudentFromDB(String name) {
        //简单演示,查询到了
        System.out.println("从数据库查询到了:"+name);
        Student student = new Student();
        student.setName(name);
        student.setAge(16);
        return student;
    }
}

测试类:

java 复制代码
public class ProtoTypeTest {
    public static void main(String[] args) {
        SjdwzMybatis sjdwzMybatis = new SjdwzMybatis();
        Student stu1 = sjdwzMybatis.queryStudent("zhangsan");
        Student stu2 = sjdwzMybatis.queryStudent("zhangsan");
        Student stu3 = sjdwzMybatis.queryStudent("zhangsan");
        Student stu4 = sjdwzMybatis.queryStudent("zhangsan");
    }
}

这样会有大量具有相同属性的student被外部创建,同时查库次数过多。

我们是否能设计一个缓存,来保存查过的内容,再查相同的记录时,可以很快拿到原来的原型对象呢?

那我们的SjdwzMybatis便变成了如下代码:

java 复制代码
public class SjdwzMybatis {
	//缓存
    private Map<String,Student> stuCache = new HashMap<>();

    /**
     * 通过name获取Student
     */
    public Student queryStudent(String name){
        if(stuCache.containsKey(name)){
            return stuCache.get(name);
        }else{
            return queryStudentFromDB(name);
        }
    }

    /**
     * 演示从数据库查Student
     */
    private Student queryStudentFromDB(String name) {
        //简单演示,查询到了
        System.out.println("从数据库查询到了:"+name);
        Student student = new Student();
        student.setName(name);
        student.setAge(16);
        //存入内存
        stuCache.put(name,student);
        return student;
    }
}

但是这是否会有问题呢?

如果我们把stu1的属性改了,那么stu2、stu3、stu4的属性也会被改变,这会影响到我们缓存里的数据,造成脏缓存数据;同时我们查出来的内容,并没有提交修改,不能就把原数据给修改掉。

原型模式

我们把Student修改成如下代码,这便是原型模式:

java 复制代码
//实现Cloneable接口,这只是一个标记,还需要重写clone()方法
public class Student implements Cloneable{
    private String name;
    private Integer age;

    //重写clone方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student student = new Student();
        student.setName(this.name);
        student.setAge(this.age);
        return student;
    }
}

然后SjdwzMybatis修改为如下代码:

java 复制代码
public class SjdwzMybatis {
    //缓存
    private Map<String,Student> stuCache = new HashMap<>();

    /**
     * 通过name获取Student
     */
    public Student queryStudent(String name) throws CloneNotSupportedException {
        if(stuCache.containsKey(name)){
            return (Student) stuCache.get(name).clone();
        }else{
            return queryStudentFromDB(name);
        }
    }

    /**
     * 演示从数据库查Student
     */
    private Student queryStudentFromDB(String name) throws CloneNotSupportedException {
        //简单演示,查询到了
        System.out.println("从数据库查询到了:"+name);
        Student student = new Student();
        student.setName(name);
        student.setAge(16);
        //存入内存
        stuCache.put(name,(Student) student.clone());
        return student;
    }
}

从数据库查出来放入缓存的对象与从缓存取出来的都是clone出来的。

可以看到,我们对stu1修改,并不会影响其他的数据了。

相关推荐
折哥的程序人生 · 物流技术专研5 小时前
Java面试85题图解版 · 特别篇:2026后端高频面试题复盘(算法底层逻辑+高并发架构设计全解析,附Java实战代码)
java·网络·数据库·算法·面试
一条泥憨鱼6 小时前
【Redis】数据类型和常用命令
java·数据库·redis·后端·缓存
云烟成雨TD6 小时前
Spring AI Alibaba 1.x 系列【78】沙箱(Sandbox)
java·人工智能·spring
程序员二叉6 小时前
【Java】 异常高频面试题精讲 | 易错点+对比总结
java·开发语言·面试
周航宇JoeZhou6 小时前
JB3-9-SpringAI(二)
java·ai·agent·多智能体·调度·智能体·观察
好家伙VCC6 小时前
Web Components主题热切换方案揭秘
java·前端
慕木沐7 小时前
Google ADK Java 1.0版本 核心机制与实战 Demo
java·开发语言·python
焦虑的说说8 小时前
秒杀系统设计方案
java
许彰午8 小时前
30_Java Stream流操作全解
java·windows·python
qq_2518364578 小时前
基于java Web网络订餐系统设计与实现 源码文档
java·开发语言·前端