经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
设计模式—创建型模式之原型模式
来源:cnblogs  作者:随机的未知  时间:2023/10/30 9:16:01  对本文有异议

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

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

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

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

  1. Student student = new Student("张三","男");

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

Student类如下:

  1. public class Student {
  2. private String name;
  3. private Integer age;
  4. public Student() {
  5. System.out.println("创建了Student对象");
  6. }
  7. //省略getter() 、 setter() toString()
  8. }

SjdwzMybatis如下:

  1. public class SjdwzMybatis {
  2. /**
  3. * 通过name获取Student
  4. */
  5. public Student queryStudent(String name){
  6. return queryStudentFromDB(name);
  7. }
  8. /**
  9. * 演示从数据库查Student
  10. */
  11. private Student queryStudentFromDB(String name) {
  12. //简单演示,查询到了
  13. System.out.println("从数据库查询到了:"+name);
  14. Student student = new Student();
  15. student.setName(name);
  16. student.setAge(16);
  17. return student;
  18. }
  19. }

测试类:

  1. public class ProtoTypeTest {
  2. public static void main(String[] args) {
  3. SjdwzMybatis sjdwzMybatis = new SjdwzMybatis();
  4. Student stu1 = sjdwzMybatis.queryStudent("zhangsan");
  5. Student stu2 = sjdwzMybatis.queryStudent("zhangsan");
  6. Student stu3 = sjdwzMybatis.queryStudent("zhangsan");
  7. Student stu4 = sjdwzMybatis.queryStudent("zhangsan");
  8. }
  9. }

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

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

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

  1. public class SjdwzMybatis {
  2. //缓存
  3. private Map<String,Student> stuCache = new HashMap<>();
  4. /**
  5. * 通过name获取Student
  6. */
  7. public Student queryStudent(String name){
  8. if(stuCache.containsKey(name)){
  9. return stuCache.get(name);
  10. }else{
  11. return queryStudentFromDB(name);
  12. }
  13. }
  14. /**
  15. * 演示从数据库查Student
  16. */
  17. private Student queryStudentFromDB(String name) {
  18. //简单演示,查询到了
  19. System.out.println("从数据库查询到了:"+name);
  20. Student student = new Student();
  21. student.setName(name);
  22. student.setAge(16);
  23. //存入内存
  24. stuCache.put(name,student);
  25. return student;
  26. }
  27. }

但是这是否会有问题呢?

修改属性

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

原型模式

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

  1. //实现Cloneable接口,这只是一个标记,还需要重写clone()方法
  2. public class Student implements Cloneable{
  3. private String name;
  4. private Integer age;
  5. //重写clone方法
  6. @Override
  7. protected Object clone() throws CloneNotSupportedException {
  8. Student student = new Student();
  9. student.setName(this.name);
  10. student.setAge(this.age);
  11. return student;
  12. }
  13. }

然后SjdwzMybatis修改为如下代码:

  1. public class SjdwzMybatis {
  2. //缓存
  3. private Map<String,Student> stuCache = new HashMap<>();
  4. /**
  5. * 通过name获取Student
  6. */
  7. public Student queryStudent(String name) throws CloneNotSupportedException {
  8. if(stuCache.containsKey(name)){
  9. return (Student) stuCache.get(name).clone();
  10. }else{
  11. return queryStudentFromDB(name);
  12. }
  13. }
  14. /**
  15. * 演示从数据库查Student
  16. */
  17. private Student queryStudentFromDB(String name) throws CloneNotSupportedException {
  18. //简单演示,查询到了
  19. System.out.println("从数据库查询到了:"+name);
  20. Student student = new Student();
  21. student.setName(name);
  22. student.setAge(16);
  23. //存入内存
  24. stuCache.put(name,(Student) student.clone());
  25. return student;
  26. }
  27. }

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

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

效果

原文链接:https://www.cnblogs.com/nicaicai/p/17796364.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号