1. 原型(Prototype)模式

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

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

04. 原型(Prototype)模式 - 图1

  1. pojo对象需要实现 Cloneable 接口 并实现clone方法
  1. public class User implements Cloneable{
  2. private String username;
  3. private int age;
  4. public User() {
  5. System.out.println("原型创建成功");
  6. }
  7. @Override
  8. protected User clone() throws CloneNotSupportedException {
  9. System.out.println("原型复制成功");
  10. User user = (User) super.clone();
  11. return user;
  12. }
  13. public String getUsername() {
  14. return username;
  15. }
  16. public void setUsername(String username) {
  17. this.username = username;
  18. }
  19. public int getAge() {
  20. return age;
  21. }
  22. public void setAge(int age) {
  23. this.age = age;
  24. }
  25. @Override
  26. public String toString() {
  27. return "User{" +
  28. "username='" + username + '\'' +
  29. ", age=" + age +
  30. '}';
  31. }
  32. }
  1. 第一次从数据库查询会创建原形对象,放入缓存为放入原形对象的克隆体,并且每次从缓存中查询后返回的对象也是克隆,避免业务对缓存中的原形进行污染(修改)。
  1. public class Mybatis {
  2. //缓存user
  3. private Map<String, User> userCache = new HashMap<>();
  4. //从数据查询数据
  5. public User getUser(String username) throws CloneNotSupportedException {
  6. User user;
  7. //缓存中没有
  8. if (!userCache.containsKey(username)) {
  9. //查询数据库
  10. user = getUserFormDb(username);
  11. } else {
  12. //从缓存中直接拿
  13. user = userCache.get(username);
  14. System.out.println("从缓存");
  15. //从缓存中拿不能直接返回 需要再次clone 再返回 防止用户直接对缓存中的数据进行修改
  16. user = user.clone();
  17. }
  18. return user;
  19. }
  20. private User getUserFormDb(String username) throws CloneNotSupportedException {
  21. System.out.println("从数据库查询" + username);
  22. User user = new User();
  23. user.setUsername(username);
  24. user.setAge(18);
  25. //注意不能直接赋值给user否则无效 因为最后返回是user 不能影响第一从数据查询的user
  26. // user = user.clone();
  27. // 放入缓存 前也要clone一下
  28. userCache.put(username, user.clone());
  29. return user;
  30. }
  31. }
  1. 调用测试
  1. public static void main(String[] args) throws CloneNotSupportedException {
  2. Mybatis mybatis = new Mybatis();
  3. User user1 = mybatis.getUser("张三");
  4. System.out.println("1==>" + user1);
  5. user1.setUsername("李四");
  6. user1.setAge(77);
  7. System.out.println("1修改了信息==>" + user1);
  8. User user2 = mybatis.getUser("张三");
  9. System.out.println("2==>"+user2);
  10. User user3 = mybatis.getUser("张三");
  11. System.out.println("4==>"+user3);
  12. User user4 = mybatis.getUser("张三");
  13. System.out.println("4==>"+user4);
  14. System.out.println(user1 == user4);
  15. }

输出结果

  1. 从数据库查询张三
  2. 原型创建成功
  3. 原型复制成功
  4. 1==>User{username='张三', age=18}
  5. 1修改了信息==>User{username='李四', age=77}
  6. 从缓存
  7. 原型复制成功
  8. 2==>User{username='张三', age=18}
  9. 从缓存
  10. 原型复制成功
  11. 4==>User{username='张三', age=18}
  12. 从缓存
  13. 原型复制成功
  14. 4==>User{username='张三', age=18}
  15. false

2. 应用场景

  • 什么场景用到?

    • 资源优化
    • 性能和安全要求
    • 一个对象多个修改者的场景。
    • 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时可以考虑使用原型模式拷贝多个对象供调用者使用。
    • 深(两个完全对象不一样的【递归克隆】,内容却完全一样)、浅(只是属性赋值)

原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。