這是我參與8月更文挑戰的第12天,活動詳情查看:8月更文挑戰java
歡迎來到今天的學習,今天咱們一塊兒來學習下實現原理很簡單,可是應用場景比較狹窄的一種模式----享元模式。多嘮叨幾句,我本月將會對java的設計模式精講,歡迎點擊頭像,關注個人專欄,我會持續更新,加油!spring
系列文章:數據庫
設計模式之單例模式設計模式
設計模式之建造者模式服務器
設計模式之代理模式markdown
設計模式之訪問者模式ide
設計模式之適配器模式post
...持續更新中
話很少說,進入正題
聽到名字,享元,很抽象,這什麼玩意,有什麼用呢。 拆開來說,享,即共享,元,能夠理解爲元數據,內存當中的數據,對象。看來是共享對象嘍
哈,立刻到七夕了,來共享下對象啊
哈哈,預祝你們七夕快樂!
迴歸正題,咱們先這樣理解該模式,拿spring的常量池、數據庫鏈接池、緩衝池等等這些都是享元模式的應用。
好比咱們每次建立字符串對象時,若是每次都建立一個新的字符串對象的話,內存開銷會很大,因此若是第一次建立了字符串對象「七夕「,下次再建立相同的字符串」七夕「時,只是把它的引用指向」七夕「,這樣就實現了」七夕「字符串再內存中的共享。
場景的話,能夠想像王者榮耀,一臺服務器鏈接了多個客戶端(多個玩家),若是每一個進去的地圖都要建立對象,那對象將無數啊。。。。因此這裏要使用享元模式,將地圖對象減小到幾個實例。
官方是這樣定義的:摒棄了在每一個對象中保存全部數據的方式,經過共享多個對象所共有的相同狀態,從而讓咱們能在有限的內存容量中載入更多對象。
咱們下面看張圖
享元類(Flyweight):定義了享元對象須要實現的公共操做方法。在該方法中會使用一個狀態做爲輸入參數,也叫外部狀態。
享元工廠類(Flyweight Factory):管理一個享元對象類的緩存池
可共享的具體享元類(ConcreteFlyweight):可以複用享元工廠內部狀態並實現享元類公共操做的具體實現類。
非共享的具體享元類(UnsharedConcreteFlyweight):不復用享元工廠內部狀態,但實現享元類的具體實現類。
咱們下面拿王者榮耀場景例子實現下
咱們都知道 王者榮耀分爲戰士,刺客,法師等等類型的英雄。下面用代碼幫你深刻理解下
//定義英雄抽象類
public abstract class HeroType {
public abstract void init();
}
//具體英雄類型
public class ConcreteHeroType extends HeroType {
private String typeName = "";
public ConcreteHeroType(String typeName) {
this.typeName = typeName;
}
@Override
public void init() {
System.out.println("英雄分類:" + typeName);
}
}
//英雄工廠類
public class HeroTypeFactory {
//用map做爲存儲
private HashMap<String, ConcreteHeroType> pool = new HashMap<>();
//得到英雄分類
public HeroType getHeroTypeCategory(String key) {
if(!pool.containsKey(key)) {
pool.put(key, new ConcreteWebSite(key));
}
return (HeroType)pool.get(key);
}
//得到英雄分類總數
public int getHeroTypeCount() {
return pool.size();
}
}
複製代碼
咱們調用下,傳幾種類型的英雄,你們看下最後的個數
public class Client {
public static void main(String[] args) {
HeroTypeFactory factory = new HeroTypeFactory();
HeroType fx = factory.getHeroTypeCategory("刺客");
fx.init();
HeroType fy = factory.getHeroTypeCategory("刺客");
fy.init();
HeroType fz = factory.getHeroTypeCategory("法師");
fz.init();
HeroType fa = factory.getHeroTypeCategory("法師");
fa.init();
HeroType fb = factory.getHeroTypeCategory("射手");
fb.init();
HeroType fc = factory.getHeroTypeCategory("射手");
fc.init();
System.out.println("英雄分類總數爲:" + factory.getWebSiteCount());
}
}
//輸出
英雄分類:刺客
英雄分類:刺客
英雄分類:法師
英雄分類:法師
英雄分類:射手
英雄分類:射手
英雄分類總數爲:3
複製代碼
是否是原本該6個對象的,如今是3個。
因此說,享元模式本質上是經過建立更多的可複用對象的共有特徵來儘量地減小建立重複對象的內存消耗。
OK 代碼到這裏就結束了
咱們來看下java當中是如何用的 ,在 Java 中,享元模式一個經常使用的場景就是,使用數據類的包裝類對象的 valueOf() 方法。好比,使用 Integer.valueOf() 方法時,實際的代碼實現中有一個叫 IntegerCache 的靜態類,它就是一直緩存了 -127 到 128 範圍內的數值,以下代碼所示,你能夠在 Java JDK 中的 Integer 類的源碼中找到這段代碼。
你會發現,享元模式本質上在使用時就是找到不可變的特徵,並緩存起來,當相似對象使用時從緩存中讀取,以達到節省內存空間的目的。
優勢:
一、第一個,減小內存消耗,節省服務器成本。 好比,當大量商家的商品圖片、固定文字(如商品介紹、商品屬性)在不一樣的網頁進行展現時,一般不須要重複建立對象,而是可使用同一個對象,以免重複存儲而浪費內存空間。
二、聚合同一類的不可變對象,提升對象複用性
感謝你的閱讀,若是你感受學到了東西,麻煩您點贊,關注。
我已經將本章收錄在專題裏,點擊下方專題,關注專欄,我會天天發表乾貨,本月我會持續輸入設計模式。
加油! 咱們下期再見!