前言
《設計模式自習室》系列,顧名思義,本系列文章帶你溫習常見的設計模式。主要內容有:
- 該模式的介紹,包括: 引子、意圖(大白話解釋) 類圖、時序圖(理論規範)
- 該模式的代碼示例:熟悉該模式的代碼長什麼樣子
- 該模式的優缺點:模式不是萬金油,不可以濫用模式
- 該模式的應用案例:瞭解它在哪些重要的源碼中被使用
該系列會逐步更新於我的博客和公眾號(博客見文章底部),也希望各位觀眾老爺能夠關注我的個人公眾號:後端技術漫談,不會錯過精彩好看的文章。
系列文章回顧
- 【設計模式自習室】開篇:為什麼我們要用設計模式?
- 【設計模式自習室】建造者模式
- 【設計模式自習室】原型模式
- 【設計模式自習室】透徹理解單例模式
- 【設計模式自習室】理解工廠模式的三種形式
- 【設計模式自習室】適配器模式
- 【設計模式自習室】裝飾模式
- 【設計模式自習室】橋接模式 Bridge Pattern:處理多維度變化
- 【設計模式自習室】門面模式 Facade Pattern
結構型——享元模式 Flyweight Pattern
引子
主要用於減少創建對象的數量,以減少內存佔用和提高性能。
在享元模式中通常會出現工廠模式,需要創建一個享元工廠來負責維護一個享元池(Flyweight Pool)用於存儲具有相同內部狀態的享元對象。
最經典的享元模式代碼:
<code>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; } }}/<code>
定義
運用共享技術有效地支持大量細粒度對象的複用。系統只使用少量的對象,而這些對象都很相似,狀態變化很小,可以實現對象的多次複用。由於享元模式要求能夠共享的對象必須是細粒度對象,因此它又稱為輕量級模式,它是一種對象結構型模式。
兩個概念:
- 內部狀態:在享元對象內部不隨外界環境改變而改變的共享部分。
- 外部狀態:隨著環境的改變而改變,不能夠共享的狀態就是外部狀態。
在享元類中要將內部狀態和外部狀態分開處理,通常將內部狀態作為享元類的成員變量,而外部狀態通過注入的方式添加到享元類中。
類圖
如果看不懂UML類圖,可以先粗略瀏覽下該圖,想深入瞭解的話,可以繼續谷歌,深入學習:
享元模式包含如下角色:
- Flyweight: 抽象享元類
- ConcreteFlyweight: 具體享元類
- UnsharedConcreteFlyweight: 非共享具體享元類
- FlyweightFactory: 享元工廠類
時序圖
時序圖(Sequence Diagram)是顯示對象之間交互的圖,這些對象是按時間順序排列的。時序圖中顯示的是參與交互的對象及其對象之間消息交互的順序。
我們可以大致瀏覽下時序圖,如果感興趣的小夥伴可以去深究一下:
代碼實現
代碼參考:
https://www.cnblogs.com/chenssy/p/3330555.html
假設:我們有一個繪圖的應用程序,通過它我們可以出繪製各種各樣的形狀、顏色的圖形,那麼這裡形狀和顏色就是內部狀態 了,通過享元模式我們就可以實現該屬性的共享了。
抽象享元類Flyweight:繪製圖像的抽象方法
<code>public
abstract
class
Shape
{public
abstract
void
draw
();}/<code>
具體享元類ConcreteFlyweight:例子中則是一種繪製某種圖像(圓形)的具體實現類,裡面的顏色則是一個可以共享的內部對象。
<code>public
class
Circle
extends
Shape
{private
String color;public
Circle
(String color)
{this
.color = color; }public
void
draw
()
{ System.out.println("畫了一個"
+ color +"的圓形"
); }}/<code>
享元工廠類FlyweightFactory:
利用了HashMap保存已經創建的顏色
<code>public
class
FlyweightFactory
{static
Map shapes =new
HashMap();public
static
ShapegetShape
(String key
){ Shape shape = shapes.get
(key); /<code>
客戶端調用:
調用相同顏色時,會直接從HashMap中取那個顏色的對象,而不會重複創建相同顏色的對象。
<code>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()+"中顏色的圓形"
); }}/<code>
使用場景舉例
如果一個系統中存在大量的相同或者相似的對象,由於這類對象的大量使用,會造成系統內存的耗費,可以使用享元模式來減少系統中對象的數量。
Integer 中的享元模式
<code>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); }/<code>
輸出是
<code>truefalse/<code>
在Java中,Integer是有緩存池的,緩存了-128~127的int對象
IntegerCache 緩存類:
<code>//是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
/<code>
其他
同理,Long也有緩存池。
String類定義為final(不可改變的),JVM中字符串一般保存在字符串常量池中,java會確保一個字符串在常量池中只有一個拷貝,這個字符串常量池在JDK6.0以前是位於常量池中,位於永久代,而在JDK7.0中,JVM將其從永久代拿出來放置於堆中。
詳細可參考:
http://laijianfeng.org/2018/09/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E4%BA%AB%E5%85%83%E6%A8%A1%E5%BC%8F%E5%8F%8A%E5%85%B8%E5%9E%8B%E5%BA%94%E7%94%A8/
優缺點
優點
- 享元模式的優點在於它能夠極大的減少系統中對象的個數。
- 享元模式由於使用了外部狀態,外部狀態相對獨立,不會影響到內部狀態,所以享元模式使得享元對象能夠在不同的環境被共享。
缺點
- 由於享元模式需要區分外部狀態和內部狀態,使得應用程序在某種程度上來說更加複雜化了。
參考
- 《HEAD FIRST設計模式》
- https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/flyweight.html
- https://www.cnblogs.com/chenssy/p/3330555.html
- http://laijianfeng.org/2018/09/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E4%BA%AB%E5%85%83%E6%A8%A1%E5%BC%8F%E5%8F%8A%E5%85%B8%E5%9E%8B%E5%BA%94%E7%94%A8/
關注我
我是一名後端開發工程師。
主要關注後端開發,數據安全,爬蟲,物聯網,邊緣計算等方向,歡迎交流。
各大平臺都可以找到我
- 微信公眾號:後端技術漫談
- Github:@qqxx6661
- CSDN:@後端技術漫談
- 知乎:@後端技術漫談
- 簡書:@後端技術漫談
- 掘金:@後端技術漫談
原創博客主要內容
- Java面試知識點複習全手冊
- 設計模式/數據結構 自習室
- Leetcode/劍指offer 算法題解析
- SpringBoot/SpringCloud菜鳥入門實戰系列
- 爬蟲相關技術文章
- 後端開發相關技術文章
- 逸聞趣事/好書分享/個人興趣
個人公眾號:後端技術漫談
公眾號:後端技術漫談.jpg
如果文章對你有幫助,不妨收藏,投幣,轉發,在看起來~
關鍵字: FlyweightFactory 設計模式 Shape