介绍
- 享元模式(Flyweight Pattern)也叫绳量模式:运用共享技术有效地支持大量粒度但对象
- 常用语系统底层但开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
- 享元模式能够解决重复对象的内存浪费问题,当系统中有大量相似对象,需要缓存池,不需要总创建对象,可以从缓存池那,降低内存,提高效率
- 享元模式经典的应用场景:连接池,String常量池、数据库连接池、缓存池等
FlyWeight : 是抽象等享元角色,他是产品等抽象类,同时定义出对象等外部状态和内部状态
- 内部状态 是存储在享元对象内部并且不会随环境改变而改变的状态,因此内部状态可以共享。
- 外部状态 是随环境改变而改变的、不可以共享的状态。享元对象的外部状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。一个外部状态与另一个外部状态之间是相互独立的。
ConcreteFlyWeight : 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务
UnshareaConcreteFlyWeight : 是不可共享角色
FlyWeightFactory : 享元工厂类,用于构建一个池容器,同时提供获取方法
案例
小型等外包项目,给客户A做一个产品展示网站,客户A等朋友感觉不错,希望做这样等产品展示网站,但要求不同
- 有客户希望以新闻但形式发布
- 有客户希望以博客但形式发布
- 有客户希望以公众号但形式发布
新建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/