深入理解23种设计模式(10) -- 享元模式

在这里插入图片描述

介绍

  • 享元模式(Flyweight Pattern)也叫绳量模式:运用共享技术有效地支持大量粒度但对象
  • 常用语系统底层但开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
  • 享元模式能够解决重复对象的内存浪费问题,当系统中有大量相似对象,需要缓存池,不需要总创建对象,可以从缓存池那,降低内存,提高效率
  • 享元模式经典的应用场景:连接池,String常量池、数据库连接池、缓存池等

在这里插入图片描述 FlyWeight : 是抽象等享元角色,他是产品等抽象类,同时定义出对象等外部状态和内部状态

  • 内部状态 是存储在享元对象内部并且不会随环境改变而改变的状态,因此内部状态可以共享。
  • 外部状态 是随环境改变而改变的、不可以共享的状态。享元对象的外部状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。一个外部状态与另一个外部状态之间是相互独立的。

ConcreteFlyWeight : 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务

UnshareaConcreteFlyWeight : 是不可共享角色

FlyWeightFactory : 享元工厂类,用于构建一个池容器,同时提供获取方法


案例

小型等外包项目,给客户A做一个产品展示网站,客户A等朋友感觉不错,希望做这样等产品展示网站,但要求不同

  1. 有客户希望以新闻但形式发布
  2. 有客户希望以博客但形式发布
  3. 有客户希望以公众号但形式发布

新建WebSite类

public abstract class WebSite {

    public abstract void use(); //抽象方法

}

新增实现类

public class ConcreteWebSite extends WebSite{

    private String type = "";

    public ConcreteWebSite(String type) {
        this.type = type;
    }

    @Override
    public void use() {
        System.out.println("网站发布形式为 :" + type);
    }
}

新增享元工厂类 (池的概念)

public class WebSiteFactory {

    /**
     * 池
     */
    private HashMap<String,ConcreteWebSite> pool = new HashMap<>();

    /**
     * 根据类型,返回一个网站,如果没有就创建,并且放入到池中
     */
    public WebSite getWebSiteCategory(String type){
        if(!pool.containsKey(type)){
            pool.put(type,new ConcreteWebSite(type));
        }
        return (WebSite)pool.get(type);
    }

    /**
     * 获取池中网站分类总数
     */
    public int getWebSiteCount(){
        return pool.size();
    }


}

客户端

public class Client {

    public static void main(String[] args) {

        //创建工厂类
        WebSiteFactory webSiteFactory = new WebSiteFactory();

        //客户要分布新闻
        WebSite webSite = webSiteFactory.getWebSiteCategory("新闻");
        webSite.use();

        //客户要分布新闻
        WebSite webSite2 = webSiteFactory.getWebSiteCategory("博客");
        webSite2.use();
    }
}

在这里插入图片描述

JDK中的应用

public final class Integer extends Number implements Comparable<Integer> {
    /**
     * A constant holding the minimum value an {@code int} can
     * have, -2<sup>31</sup>.
     */
    @Native public static final int   MIN_VALUE = 0x80000000;

    /**
     * A constant holding the maximum value an {@code int} can
     * have, 2<sup>31</sup>-1.
     */
    @Native public static final int   MAX_VALUE = 0x7fffffff;
	……
}
  • 我们都知道Integer有一个初始化值默认范围(-128到127),如果在这个范围内Integer.valueOf(n)这个方法返回缓存中的值,否则创建一个新的Integer对象。源码如下:
    
	// 在一个区间之内,直接用IntegerCache.cache[]数组里面的数返回,否则new 一个新对象。
	public static Integer valueOf(int i) {
	        if (i >= IntegerCache.low && i <= IntegerCache.high)
	            return IntegerCache.cache[i + (-IntegerCache.low)];
	        return new Integer(i);
	    }
private static class IntegerCache {
        static final int low = -128;  //Integer的最低值
        static final int high;        //最高值
        static final Integer cache[];   //缓存数组

        static {
            // high value may be configured by property
            int h = 127;
            ////这里可以在运行时设置虚拟机参数来确定
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    //不能小于127
                    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;

            cache = new Integer[(high - low) + 1];
            int j = low;
            //循环将区间的数赋值给cache[]数组
            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() {}
    }

用一个Integer数组先缓存了,后面如果是是在区间内的数直接从缓存数组中取,否则才构造新的Integer



github Demo地址 : ~~~传送门~~~

个人博客地址:http://blog.yanxiaolong.cn/

end
  • 作者:yxl(联系作者)
  • 发表时间:2021-02-21 12:17
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 转载声明:如果是转载栈主转载的文章,请附上原文链接
  • 公众号转载:请在文末添加作者公众号二维码(公众号二维码见右边,欢迎关注)
  • 评论