亨元模式介紹
亨元模式适用場景
面向對象技術可以很好的解決一些靈活性或可拓展性的問題,但在很多情況下需要在系統中增加類和對象的個數。當對象數量太多時,将導緻對象建立及垃圾回收的代價過高,造成性能下降等問題。亨元模式通過共享相同或者類似的細粒度對象解決這一類問題。
亨元模式定義
亨元模式(Flyweight Pattern),又稱輕量級模式(這也是其英文名FlyWeight的原因),通過共享技術有效的實作了大量細粒度對象的服用。
亨元模式類圖
亨元模式類圖如下:
亨元模式角色劃分
- FlyWeight亨元接口或者(抽象亨元類),定義共享接口
- ConcreteFlyWeight:具體亨元類,該執行個體将實作共享
- UnsharedConcreteFlyWeight:非共享亨元實作類
- FlyWeightFactory:亨元工廠類,控制執行個體的建立和共享。
内部狀态 VS 外部狀态
- 内部狀态是存儲在亨元對象内部,一般在構造是确定或通過setter設定,并且不會随環境改變而改變的狀态,是以内部狀态可以共享。
- 外部狀态是随環境變化而變化,不可以共享的狀态。外部狀态在需要使用時通過用戶端傳入亨元對象。外部狀态必須由用戶端儲存。
亨元模式執行個體分析
亨元接口,定義共享接口
public interface FlyWeight {
void action(String externalState);
}
具體亨元類,實作亨元接口。該類的對象将被複用
public class ConcreteFlyWeight implements FlyWeight {
private String name;
public ConcreteFlyWeight(String name) {
this.name = name;
}
@Override
public void action(String externalState) {
System.out.println(String.format("name = %s, outerState = %s", this.name, externalState));
}
}
亨元模式中,最關鍵的是亨元工廠。它将維護已建立的亨元執行個體,并通過執行個體标記(一般用内部狀态)去索引對應的執行個體。當目标對象未建立時,亨元工廠負責建立執行個體并将其加入标記-對象映射。當目标對象已建立時,亨元工廠直接傳回已有執行個體,實作對象的複用。
public class FlyWeightFactory {
private static ConcurrentHashMap<String,FlyWeight> allFlyWeight = new ConcurrentHashMap<>();
public static FlyWeight getFlyWeight(String name) {
if(allFlyWeight.get(name) == null){
synchronized (allFlyWeight){
if(allFlyWeight.get(name) == null){
System.out.println(String.format("Instance of name = %s does not exist, creating it",name));
FlyWeight flyWeight = new ConcreteFlyWeight(name);
System.out.println(String.format("Instance of name = %s created",name));
allFlyWeight.put(name, flyWeight);
}
}
}
return allFlyWeight.get(name);
}
}
從上面的代碼中可以看到,亨元模式中對象的複用完全依靠亨元工廠。同時本例中實作了對象建立的懶加載。并且為了保證線程安全,本文使用的雙重檢查(Double Check)。
本例中,
name
可以認為時内部狀态,在構造是确定。
externalState
屬于外部狀态,由用戶端在調用時傳入。
測試類
public class FlyWeightTest {
public static void main(String[] args) {
FlyWeight sjj = FlyWeightFactory.getFlyWeight("sjj");
sjj.action("wj");
}
}
結果輸出
Instance of name = sjj does not exist, creating it
Instance of name = sjj created
name = sjj, outerState = wj
亨元模式分析
亨元模式優點
- 亨元模式的外部狀态相對獨立,使得對象可以在不同的環境中被複用(共享對象可以使用不同的外部環境)
- 亨元模式可共享相同或類似的細粒度對象,進而減少了記憶體消耗,同時降低了對象建立與垃圾回收的開銷
亨元模式缺點
- 外部狀态由用戶端儲存,共享對象讀取外部狀态的開銷可能比較大
- 亨元模式要求将内部狀态與外部狀态分離,這使得程式的邏輯複雜化,同時也增加了狀态維護成本。