享元模式也是一種結構型模式。緩存
享元模式的原理和實現都很簡單,可是應用場景卻相對狹窄,它和如今咱們所熟知的緩存模式、池化模式有所聯繫,卻又有不一樣。服務器
享元模式強調的是空間效率,好比,一個很大的數據模型對象如何儘可能少佔用內存並提供可複用的能力;而緩存模式強調的是時間效率,好比,緩存秒殺的活動數據和庫存數據等,數據可能會佔用不少內存和磁盤空間,可是得保證在大促活動開始時要能及時響應用戶的購買需求。也就是說,二者本質上解決的問題類型是不一樣的。markdown
使用共享對象可有效地支持大量地細粒度對象。ide
摒棄了在每一個對象中保存全部數據的方式,經過共享多個對象所共有的相同狀態,從而讓咱們能在有限的內存容量中載入更多對象。網站
從這個定義中你能夠發現,享元模式要解決的核心問題就是節約內存空間,使用的辦法是找出類似對象之間的共有特徵,而後複用這些特徵。this
先了解下內部狀態和外部狀態的概念spa
內部狀態:不會隨環境改變而改變的狀態,俗稱不可變對象。好比,在 Java
中 Integer
對象初始化就是緩存 -127 到 128 的值,不管怎麼使用 Integer
,這些值都不會變化。code
外部狀態:隨環境改變而改變的狀態。一般是某個對象所獨有的,不能被共享,所以,也只能由客戶端保存。之因此須要外部狀態就是由於客戶端須要不一樣的定製化操做。orm
//享元類 public interface Flyweight { void operation(int state); }對象
//享元工廠類 public class FlyweighFactory { // 定義一個池容器 public Map<String,Flyweight> pool = new HashMap<>();
public FlyweighFactory() {
pool.put("A", new ConcreteFlyweight("A"));//將對應的內部狀態添加進去
pool.put("B", new ConcreteFlyweight("B"));
pool.put("C", new ConcreteFlyweight("C"));
}
//根據內部狀態來查找值
public Flyweight getFlyweight(String key) {
if (pool.containsKey(key)) {
System.out.println("===享元池中有,直接複用,key:"+key);
return pool.get(key);
} else {
System.out.println("===享元池中沒有,從新建立並複用,key:"+key);
Flyweight flyweightNew = new ConcreteFlyweight(key);
pool.put(key,flyweightNew);
return flyweightNew;
}
}
複製代碼
}
//共享的具體享元類 public class ConcreteFlyweight implements Flyweight { private String uniqueKey; public ConcreteFlyweight(String key) { this.uniqueKey = key; }
@Override
public void operation(int state) {
System.out.printf("=== 享元內部狀態:%s,外部狀態:%s%n",uniqueKey,state);
}
複製代碼
} //非共享的具體享元類 public class UnsharedConcreteFlyweight implements Flyweight {
private String uniqueKey;
public UnsharedConcreteFlyweight(String key) {
this.uniqueKey = key;
}
@Override
public void operation(int state) {
System.out.println("=== 使用不共享的對象,內部狀態:"+uniqueKey+",外部狀態:"+state);
}
複製代碼
}
就是利用Map
緩存了應該被緩存的類,key
相同就複用對象。
Java
中也有相似操做,好比,在 Java
中 Integer
對象初始化就是緩存 -127 到 128 的值,不管怎麼使用 Integer
,這些值都不會變化。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
複製代碼
系統中存在大量重複建立的對象。好比,同一個商品的展現圖片、詳情介紹、文字介紹等
相關性很高而且能夠複用的對象。好比,公司的組織結構人員基本信息、網站的分類信息
須要緩衝池的場景
減小內存消耗,節省服務器成本
聚合同一類的不可變對象,提升對象複用性
equals
和hashCode
方法,因此外部狀態最好以Java
基本類型爲標誌