一,享元模式
享元模式:
- 又叫蝇量模式,运用共享技术有效的支持大量的细粒度的对象;
- 常用于系统底层的开发,解决系统性的问题,如数据库连接池,如果没有再创建一个,有就直接拿来用;
- 能够解决重复创建对象的内存浪费问题,当系统中有大量相似对象,需要缓冲池时,不需要总是创建新对象,从缓冲池直接获取,降低系统内存提高效率;
- 经典的场景就是池技术,如数据库连接池、string常量池、缓冲池等;
内部状态: 对象共享出来的信息,存储在享元对象内部,不随环境改变而改变,如:围棋的棋子颜色;
外部状态: 不可共享的,对象依赖的一个标记,随环境而改变,如:围棋的棋子位置;
二,原理类图
意图: 运用共享技术有效地支持大量细粒度的对象。
适用性:
- 一个应用程序使用了大量的对象。完全由于使用大量的对象,造成很大的存储开销。
- 对象的大多数状态都可变为外部状态。如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
- 应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
三,实例
FlyWeight(抽象的享元角色)
package com.neei.flyweight;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 20:59
* @Description: 游学网
* @throws:
*/
public abstract class WebSite {
abstract void useWeb(User user);
}
ConcreteFlyWeight(共享具体实现)
package com.neei.flyweight;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:01
* @Description: 游学网
* @throws:
*/
public class ConcreteWebSite extends WebSite {
private String type;
public ConcreteWebSite(String type) {
this.type = type;
}
@Override
void useWeb(User user) {
System.out.println(user.getName() + "打开的网站:" + type);
}
}
UnsharedConcreteFlyWeight(非共享具体实现)
package com.neei.flyweight;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:13
* @Description: 游学网
* @throws:
*/
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
FlyWeightFactory(享元工厂类)
package com.neei.flyweight;
import java.util.HashMap;
import java.util.Map;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:02
* @Description: 游学网
* @throws:
*/
public class WebSiteFactory {
private Map<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 int size() {
return pool.size();
}
}
调用
package com.neei.flyweight;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/11 21:05
* @Description: 游学网
* @throws:
*/
public class Client {
public static void main(String[] args) {
WebSiteFactory factory = new WebSiteFactory();
WebSite webSite = factory.getWebSite("淘宝");
webSite.useWeb(new User("张三"));
WebSite webSite1 = factory.getWebSite("天猫");
webSite1.useWeb(new User("李四"));
WebSite webSite2 = factory.getWebSite("淘宝");
webSite2.useWeb(new User("王五"));
WebSite webSite3 = factory.getWebSite("淘宝");
webSite3.useWeb(new User("赵六"));
System.out.println("池中总数:"+factory.size());
}
}
四,源码分析
JDK源码中使用的享元模式,如java.lang.Integer#valueOf;
private static class IntegerCache {
static final int low = -128;
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);
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;
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() {}
}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}