一,享元模式
享元模式:
- 又叫蠅量模式,運用共享技術有效的支持大量的細粒度的對象;
- 常用於系統底層的開發,解決系統性的問題,如數據庫連接池,如果沒有再創建一個,有就直接拿來用;
- 能夠解決重複創建對象的內存浪費問題,當系統中有大量相似對象,需要緩衝池時,不需要總是創建新對象,從緩衝池直接獲取,降低系統內存提高效率;
- 經典的場景就是池技術,如數據庫連接池、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);
}