• 设计模式共享对象(享元模式)


    享元模式

    1.基本介绍

    • 也叫蝇量模式:运用共享技术有效的支持大量细粒度对象
    • 常用于系统底层开发,解决系统性能问题,比如数据库连接池,可以将共用对象直接拿出来用,避免重新创建
    • 能够解决重复对象的内存浪费问题,当系统中有大量相似对象,需要缓冲池时,不需要重新创建,直接从缓冲池中获取
    • 享元模式是池技术的重要实现,String常量池、数据库连接池、缓冲池

    2.原理类图

    • FlyWeightFactory:享元的工厂类,用于构建一个池容器(集合),同时提供从池中获取对象方法
    • FlyWeight:抽象的享元角色,是产品的抽象,同时定义出对象的外部状态内部状态 的接口或实现
    • concreteFlyWeight:具体的享元角色,实现抽象角色定义相关业务
    • unSharedConcreteFlyWeight:不可共享角色,一般不会出现在享元工厂中

    3.内部状态和外部状态

    • 享元模式提出了两个要求:细粒度和共享对象;这里就涉及到内部状态和外部状态了,即将信息分成了两个部分

    内部状态

    • 对象共享出来的信息,存储在享元对象内不会随着环境的变化而变化
    • 以围棋为例,棋子的颜色无论是谁来下棋,都是黑白,属于较为稳定的信息,因此颜色可视为内部状态

    外部状态

    • 对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态
    • 以围棋为例,每个棋子的坐标是会根据下棋人的不同而不同的,属于不稳定的信息,因此坐标可视为外部状态

    小结

    • 即假设开发一个围棋的游戏,一共361个棋子,传统模式就是创建361个棋子对象,而使用享元模式我们只需要两个实例,一黑一白,加上外部状态的位置即可

    4.案例

    案例需求

    网站外包,根据不同的用户来提供它们需要的网站

    案例类图设计

    案例代码实现

    WebSite设计实现

    public interface WebSite {
    	//网站调用方法,即享元角色的使用
    	public void use(User user);
    }
    

    ConcreteWebSite实现

    public class ConcreteWebSite implements WebSite{
    	//网站发布的形式,享元角色的内部状态
    	private String type = "";
    	public ConcreteWebSite(String type) {
    		this.type = type;
    	}
    	@Override
    	public void use(User user) {
    		System.out.println("网站以【"+type+"】的形式使用中...【使用者:"+user.getName()+"】");
    	}
    
    }
    

    WebSiteFactory工厂实现

    public class WebSiteFactory {
    	//模拟一个池
    	private HashMap<String, WebSite> pool = new HashMap<>();
    	//从池中取出享元角色,没有则创建放入
    	public WebSite getWebSite(String type) {
    		if(!pool.containsKey(type)) {
    			pool.put(type, new ConcreteWebSite(type));
    		}
    		return pool.get(type);
    	}
    }
    

    调用时附加上外部状态

    public class Client {
    	public static void main(String[] args) {
    		//创建享元工厂
    		WebSiteFactory factory = new WebSiteFactory();	
    		//获取享元角色
    		WebSite webSite1 = factory.getWebSite("新闻");
    		//使用附加上外部信息
    		webSite1.use(new User("Tom"));
    		//获取不存在的,直接创建
    		WebSite webSite2 = factory.getWebSite("博客");
    		//外部信息
    		webSite2.use(new User("Lin"));
    	}
    }
    

    5.Integer中的享元模式分析

    Integer的Integer.valueOf()方法在-128~127的范围中使用的是享元模式

    • 首先看到该方法,该方法的调用了享元工厂对象,他将得到的int值获取,判断是否符合池中共享对象的范畴,有则返回,没有则新建一个返回

          public static Integer valueOf(int i) {
              //可以发现,在IntegerCache中有对共享资源的一个限制
              if (i >= IntegerCache.low && i <= IntegerCache.high)
                  return IntegerCache.cache[i + (-IntegerCache.low)];
              return new Integer(i);
          }
      
    • IntegerCache对象充当了一个享元工厂,可以发现最小值为-128,最大值为127,只有在这个范围内才是享元模式管理的范畴

         private static class IntegerCache {
              static final int low = -128;
              static final int high;
             //真正储存Integer对象的容器--池
              static final Integer cache[];
             //静态代码块初始化参数
              static {
                  int h = 127;
                  String integerCacheHighPropValue =
                      sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
                  if (integerCacheHighPropValue != null) {
                      try {
                          int i = parseInt(integerCacheHighPropValue);
                          i = Math.max(i, 127);
                          // Maximum array size is Integer.MAX_VALUE
                          h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                      } catch( NumberFormatException nfe) {
                          // If the property cannot be parsed into an int, ignore it.
                      }
                  }
                  high = h;
                  //往池中添加-128~127的Inter对象
                  cache = new Integer[(high - low) + 1];
                  int j = low;
                  for(int k = 0; k < cache.length; k++)
                      cache[k] = new Integer(j++);
      
                  // range [-128, 127] must be interned (JLS7 5.1.7)
                  assert IntegerCache.high >= 127;
              }
              private IntegerCache() {}
          }
      
      

    6.小结

    • “享”代表共享,“元”代表对象
    • 系统有大量对象,且这些对象消耗大量内存,对象的状态大部分可以外部化时,我们就可以考虑选用享元模式
    • 用唯一标识码判断,如果内存中有,则返回这个唯一标识码所表示的对象,用HashMap/HashTable存储
    • 享元模式大大减少了对象的创建,降低了程序内存的占用,提高效率
    • 使用享元模式要注意的是,享元模式提高了系统的复杂度,需要分理出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态改变。
    • 注意划分内部状态和外部状态,一般需要一个工厂类加以控制
  • 相关阅读:
    97. Interleaving String
    96. Unique Binary Search Trees
    95. Unique Binary Search Trees II
    94. Binary Tree Inorder Traversal
    odoo many2many字段 指定打开的form视图
    docker sentry 配置文件位置
    postgres 计算时差
    postgres 字符操作补位,字符切割
    postgres判断字符串是否为时间,数字
    odoo fields_view_get
  • 原文地址:https://www.cnblogs.com/JIATCODE/p/13200724.html
Copyright © 2020-2023  润新知