设计模式:享元模式(Flyweight)
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
歡迎跳轉到本文的原文鏈接:https://honeypps.com/design_pattern/flyweight/
?運用共享技術有效地支持大量細粒度的對象。又名“蠅量模式”。
?在Java語言中,String類型就是使用了享元模式。String對象是final類型,對象一旦創建就不可改變。在JAVA中字符串常量都是存在常量池中的,Java會確保一個字符串常量在常量池中只有一個拷貝。譬如:
?輸出結果:true。這就說明了a和b量引用都指向了常量池中的同一個字符串常量“abc"。這樣的設計避免了在創建N多相同對象時所產生的不必要的大量的資源消耗。
?享元模式采用一個共享來避免大量擁有相同內容對象的開銷。這種開銷最常見、最直觀的就是內存的消耗。享元對象能做到共享的關鍵是區分內蘊狀態(Internal State)和外蘊狀態(External State)。
?一個內蘊狀態是存儲在享元對象內部的,并且是不會隨環境的改變而有所不同。因此,一個享元可以具有內蘊狀態并且可以共享。
?一個外蘊狀態是隨環境的改變而改變的、不可以共享的。享元對象的外蘊狀態必須由客戶端保存,并在享元對象被創建之后,在需要使用的時候再傳入到享元對象內部。外蘊狀態不可以影響享元對象的內蘊狀態,他們是相互獨立的。
?享元模式可以分成單純享元模式和復合享元模式。
##單純享元模式
包含的角色:
舉個簡單例子
1 抽象享元角色
2 具體享元角色
public class ConcreteFlyweight implements Flyweight {private String str;public ConcreteFlyweight(String str){this.str = str;}@Overridepublic void operation(String state){System.out.println("內蘊狀態:"+str);System.out.println("外蘊狀態:"+state);} }3 享元工廠角色
public class FlyWeightFactory {private Map<String,ConcreteFlyweight> flyWeights = new HashMap<String, ConcreteFlyweight>();public ConcreteFlyweight factory(String str){ConcreteFlyweight flyweight = flyWeights.get(str);if(null == flyweight){flyweight = new ConcreteFlyweight(str);flyWeights.put(str, flyweight);}return flyweight;}public int getFlyWeightSize(){return flyWeights.size();} }4 測試代碼
FlyWeightFactory factory = new FlyWeightFactory();Flyweight f1 = factory.factory("a");Flyweight f2 = factory.factory("b");Flyweight f3 = factory.factory("a");f1.operation("a fly weight");f2.operation("b fly weight");f3.operation("c fly weight");System.out.println(f1 == f3);System.out.println(factory.getFlyWeightSize());輸出結果:
內蘊狀態:a 外蘊狀態:a fly weight 內蘊狀態:b 外蘊狀態:b fly weight 內蘊狀態:a 外蘊狀態:c fly weight true 2##復合享元模式
?在單純享元模式中,所有的享元對象都是單純享元對象,也就是說都是可以直接共享的,將一些單純享元使用合成模式加以復合,形成復合享元對象。這樣的復合享元對象本身不能共享,但是它們可以分解成單純享元對象,而后者則可以共享。
?包含的角色
變更上面的例子:
1 抽象享元角色(同上)
2 具體享元角色(同上)
3 復合享元角色
?復合享元對象是由單純享元對象通過復合而成的,因此提供了add()這樣的聚集管理方法。由于一個復合享元對象具有不同的聚集元素,這些聚集元素在復合享元對象被創建之后加入,這本身就意味著復合享元對象的狀態是會改變的,因此復合享元對象是不能共享的。
4 享元工廠角色提供兩種不同的方法,一種用于提供單純享元對象,另一種用于提供復合享元對象。
public class FlyweightCompositeFactory {private Map<String,Flyweight> flyWeights = new HashMap<String, Flyweight>();public Flyweight factory(List<String> compositeStates){ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight();for(String s: compositeStates){compositeFly.add(s, this.factory(s));}return compositeFly;}public Flyweight factory(String s){Flyweight fly = flyWeights.get(s);if(fly == null){fly = new ConcreteFlyweight(s);flyWeights.put(s, fly);}return fly;} }5 測試代碼
List<String> list = new ArrayList<String>();list.add("a");list.add("b");list.add("c");list.add("a");list.add("b");FlyweightCompositeFactory factory = new FlyweightCompositeFactory();Flyweight f1 = factory.factory(list);Flyweight f2 = factory.factory(list);f1.operation("Composite Call");System.out.println("=======");System.out.println("復合享元模式是否可以共享對象:"+(f1 == f2));String str = "a";Flyweight f3 = factory.factory(str);Flyweight f4 = factory.factory(str);System.out.println("單純享元模式是否可以共享對象:"+(f3 == f4));運行結果:
內蘊狀態:b 外蘊狀態:Composite Call 內蘊狀態:c 外蘊狀態:Composite Call 內蘊狀態:a 外蘊狀態:Composite Call ======= 復合享元模式是否可以共享對象:false 單純享元模式是否可以共享對象:true?由上例可知:一個符合享元對象的所有單純享元對象元素的外蘊狀態都是與復合享元對象的外蘊狀態相等的。一個復合享元對象所含有的單純享元對象的內蘊狀態一般是不相等的。復合享元對象是不能共享的。單純享元對象是可以共享的。
?舉個更形象點的例子,比如去飯店吃飯,菜單只有一份,而每個顧客點菜品卻各不相同,但是肯定會有重復,我們用上述的享元模式嘗試下模擬代碼情形:
FlyweightCompositeFactory factory = new FlyweightCompositeFactory();List<String> menuList = Arrays.asList("魚香肉絲","宮保雞丁","杭椒牛柳","平鍋魚","番茄炒蛋");Flyweight f1 = factory.factory(menuList.subList(0, 2));Flyweight f2 = factory.factory(menuList.subList(2, 3));f1.operation("customer1的菜單");System.out.println("================");f2.operation("customer2的菜單");代碼輸出:
內蘊狀態:魚香肉絲 外蘊狀態:customer1的菜單 內蘊狀態:宮保雞丁 外蘊狀態:customer1的菜單 ================ 內蘊狀態:杭椒牛柳 外蘊狀態:customer2的菜單優缺點
優點:大幅度降低內存中對象的數量
缺點:享元模式使得系統更加復雜。為了使對象可以共享,需要將一些狀態外部化,這使得程序的邏輯復雜化。享元模式將享元對象的狀態外部化,而讀取外部狀態使得運行時間稍微變長。
Jdk中的享元模式
java.lang.Integer#valueOf(int)
java.lang.Boolean#valueOf(boolean)
java.lang.Byte#valueOf(byte)
java.lang.Character#valueOf(boolean)
參考資料
歡迎跳轉到本文的原文鏈接:https://honeypps.com/design_pattern/flyweight/
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
總結
以上是生活随笔為你收集整理的设计模式:享元模式(Flyweight)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式:组合模式(Composite)
- 下一篇: 设计模式:模板方法模式(Template