《設計模式自習室》系列,顧名思義,本系列文章帶你溫習常見的設計模式。主要內容有:html
該系列會逐步更新於個人博客和公衆號(博客見文章底部),也但願各位觀衆老爺可以關注個人我的公衆號:後端技術漫談,不會錯過精彩好看的文章。java
主要用於減小建立對象的數量,以減小內存佔用和提升性能。面試
在享元模式中一般會出現工廠模式,須要建立一個享元工廠來負責維護一個享元池(Flyweight Pool)用於存儲具備相同內部狀態的享元對象。算法
最經典的享元模式代碼:後端
class FlyweightFactory { //定義一個HashMap用於存儲享元對象,實現享元池 private HashMap flyweights = newHashMap(); public Flyweight getFlyweight(String key){ //若是對象存在,則直接從享元池獲取 if(flyweights.containsKey(key)){ return(Flyweight)flyweights.get(key); } //若是對象不存在,先建立一個新的對象添加到享元池中,而後返回 else { Flyweight fw = newConcreteFlyweight(); flyweights.put(key,fw); return fw; } } }
運用共享技術有效地支持大量細粒度對象的複用。系統只使用少許的對象,而這些對象都很類似,狀態變化很小,能夠實現對象的屢次複用。因爲享元模式要求可以共享的對象必須是細粒度對象,所以它又稱爲輕量級模式,它是一種對象結構型模式。設計模式
兩個概念:數組
在享元類中要將內部狀態和外部狀態分開處理,一般將內部狀態做爲享元類的成員變量,而外部狀態經過注入的方式添加到享元類中。緩存
若是看不懂UML類圖,能夠先粗略瀏覽下該圖,想深刻了解的話,能夠繼續谷歌,深刻學習:
安全
享元模式包含以下角色:微信
時序圖(Sequence Diagram)是顯示對象之間交互的圖,這些對象是按時間順序排列的。時序圖中顯示的是參與交互的對象及其對象之間消息交互的順序。
咱們能夠大體瀏覽下時序圖,若是感興趣的小夥伴能夠去深究一下:
代碼參考:
https://www.cnblogs.com/chenssy/p/3330555.html
假設:咱們有一個繪圖的應用程序,經過它咱們能夠出繪製各類各樣的形狀、顏色的圖形,那麼這裏形狀和顏色就是內部狀態了,經過享元模式咱們就能夠實現該屬性的共享了。
抽象享元類Flyweight:繪製圖像的抽象方法
public abstract class Shape { public abstract void draw(); }
具體享元類ConcreteFlyweight:例子中則是一種繪製某種圖像(圓形)的具體實現類,裏面的顏色則是一個能夠共享的內部對象。
public class Circle extends Shape{ private String color; public Circle(String color){ this.color = color; } public void draw() { System.out.println("畫了一個" + color +"的圓形"); } }
享元工廠類FlyweightFactory:
利用了HashMap保存已經建立的顏色
public class FlyweightFactory{ static Map<String, Shape> shapes = new HashMap<String, Shape>(); public static Shape getShape(String key){ Shape shape = shapes.get(key); //若是shape==null,表示不存在,則新建,而且保持到共享池中 if(shape == null){ shape = new Circle(key); shapes.put(key, shape); } return shape; } public static int getSum(){ return shapes.size(); } }
客戶端調用:
調用相同顏色時,會直接從HashMap中取那個顏色的對象,而不會重複建立相同顏色的對象。
public class Client { public static void main(String[] args) { Shape shape1 = FlyweightFactory.getShape("紅色"); shape1.draw(); Shape shape2 = FlyweightFactory.getShape("灰色"); shape2.draw(); Shape shape3 = FlyweightFactory.getShape("綠色"); shape3.draw(); Shape shape4 = FlyweightFactory.getShape("紅色"); shape4.draw(); Shape shape5 = FlyweightFactory.getShape("灰色"); shape5.draw(); Shape shape6 = FlyweightFactory.getShape("灰色"); shape6.draw(); System.out.println("一共繪製了"+FlyweightFactory.getSum()+"中顏色的圓形"); } }
若是一個系統中存在大量的相同或者類似的對象,因爲這類對象的大量使用,會形成系統內存的耗費,可使用享元模式來減小系統中對象的數量。
public static void main(String[] args) { Integer i1 = 12 ; Integer i2 = 12 ; System.out.println(i1 == i2); Integer b1 = 128 ; Integer b2 = 128 ; System.out.println(b1 == b2); }
輸出是
true false
在Java中,Integer是有緩存池的,緩存了-128~127的int對象
IntegerCache 緩存類:
//是Integer內部的私有靜態類,裏面的cache[]就是jdk事先緩存的Integer。 private static class IntegerCache { static final int low = -128;//區間的最低值 static final int high;//區間的最高值,後面默認賦值爲127,也能夠用戶手動設置虛擬機參數 static final Integer cache[]; //緩存數組 static { // high value may be configured by property int h = 127; //這裏能夠在運行時設置虛擬機參數來肯定h :-Djava.lang.Integer.IntegerCache.high=250 String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) {//用戶設置了 int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127);//雖然設置了可是仍是不能小於127 // 也不能超過最大值 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } high = h; cache = new Integer[(high - low) + 1]; int j = low; //循環將區間的數賦值給cache[]數組 for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
同理,Long也有緩存池。
String類定義爲final(不可改變的),JVM中字符串通常保存在字符串常量池中,java會確保一個字符串在常量池中只有一個拷貝,這個字符串常量池在JDK6.0之前是位於常量池中,位於永久代,而在JDK7.0中,JVM將其從永久代拿出來放置於堆中。
詳細可參考:
因爲享元模式須要區分外部狀態和內部狀態,使得應用程序在某種程度上來講更加複雜化了。
參考
我是一名後端開發工程師。
主要關注後端開發,數據安全,爬蟲,物聯網,邊緣計算等方向,歡迎交流。
公衆號:後端技術漫談.jpg
若是文章對你有幫助,不妨收藏,投幣,轉發,在看起來~