Java設計模式(13):享元模式(蠅量模式)
13,享元模式(FlyWeight)
13.1,問題引入
13.1.1,展示網站專案需求
小型的外包專案,給客戶A做一個產品展示網站,客戶A的朋友覺得效果不錯,也需要這樣的產品展示網站,但是需求有些變化:
- 有客戶要求以新聞的形式釋出
- 有客戶要求以部落格的形式釋出
- 有客戶要求以微信小程式的形式釋出
13.1.2,傳統方式解決網站專案
- 直接將專案複製一份,根據不同客戶的需求,進行定製化修改
13.1.3,問題分析
- 需要的網站相似度很高,而且都不是高訪問量網站,如果分成多個虛擬機器進行部署,相當於一個相同網站的例項有很多,造成伺服器資源浪費
- 可以將程式碼和資料整合到一個網站中,對於硬碟,記憶體,CPU等資源進行共享,減少伺服器資源
13.2,享元模式基本概述
- 享元模式,也叫蠅量模式:運用共享技術有效的支援大量細粒度的物件。“享”表示共享,“元”表示物件
- 常用於系統底層開發,解決系統的效能問題。像資料庫連線池,裡面都是已經建立好的資料庫連線物件,這些連線物件在我們需要的時候可以直接拿來用,避免重新建立,如果沒有我們需要的,則新建立一個
- 享元模型能夠解決重複物件的記憶體浪費問題,當系統中存在大量的物件需要緩衝池時。不需要不斷的建立新物件,可以直接從緩衝池中拿。可以降低系統記憶體,提升效率。如JVM中的常量池
- 在JDK中的應用,
Integer
的快取池-127~127
13.3,類圖
FlyWeightFactory
:享元工廠,用於提供一個池容器,並從池中獲取物件的方法IFlyWeight
:享元抽象介面,提供產品的抽象介面,並同時定義出物件內部狀態和外部狀態的介面和實現FlyWeight
:具體享元角色,共享的角色,即具體的產品類,實現內部狀態,內部狀態角色是被享元工廠託管的角色UnsharedFlyWeight
:特殊享元角色,不可共享的角色,實現外部狀態,該部分不會被享元工廠託管
13.4,內部狀態和外部狀態
- 享元模式提出了兩個要求:細粒度和共享物件,這就涉及到內部狀態和外部狀態了
- 內部狀態是物件共享出來的資訊,儲存在享元物件內並不會隨著環境的不同而改變
- 外部狀態是物件得以依賴的一個標記,隨環境改變而改變,不可共享的狀態
- 舉例:圍棋理論上是有361個空位可以放棋子,每盤棋都有可能有兩三百個棋子產生,因為記憶體空間有限,一臺伺服器很難支撐更多的玩家玩圍棋遊戲,如果用享元模式來處理棋子,則棋子物件減少到兩個,空棋盤共用,具體的棋盤佈局是特殊角色
13.5,程式碼實現
-
IFlyWeight
:享元角色頂層類package com.self.designmode.flyweight; /** * 享元模式頂層介面 * @author PJ_ZHANG * @create 2020-08-22 21:16 **/ public interface IFlyWeight { void use(); void setUnsharedFlyWeight(UnsharedFlyWeight unsharedFlyWeight); }
-
FlyWeight
:具體角色package com.self.designmode.flyweight; /** * 享元模式: 具體角色 * @author PJ_ZHANG * @create 2020-08-22 21:20 **/ public class FlyWeight implements IFlyWeight { private String type = ""; private UnsharedFlyWeight unsharedFlyWeight = null; public FlyWeight(String type) { this.type = type; } @Override public void use() { System.out.println("享元具體角色: " + type); if (null != unsharedFlyWeight) { unsharedFlyWeight.use(); } } @Override public void setUnsharedFlyWeight(UnsharedFlyWeight unsharedFlyWeight) { this.unsharedFlyWeight = unsharedFlyWeight; } }
-
UnsharedFlyWeight
:特殊角色package com.self.designmode.flyweight; /** * 享元模式: 特殊角色 * @author PJ_ZHANG * @create 2020-08-22 21:26 **/ public class UnsharedFlyWeight implements IFlyWeight { private String type = ""; private UnsharedFlyWeight unsharedFlyWeight = null; public UnsharedFlyWeight(String type) { this.type = type; } @Override public void use() { System.out.println("享元特殊角色: " + type); if (null != unsharedFlyWeight) { unsharedFlyWeight.use(); } } @Override public void setUnsharedFlyWeight(UnsharedFlyWeight unsharedFlyWeight) { this.unsharedFlyWeight = unsharedFlyWeight; } }
-
FlyWeightFactory
:享元工廠package com.self.designmode.flyweight; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 享元工廠, 獲取具體享元角色 * @author PJ_ZHANG * @create 2020-08-22 21:16 **/ public class FlyWeightFactory { private static Map<String, FlyWeight> map = new ConcurrentHashMap<>(16); private static Map<String, UnsharedFlyWeight> unsharedMap = new ConcurrentHashMap<>(16); public static FlyWeight getFlyWeight(String type) { if (!map.containsKey(type)) { map.put(type, new FlyWeight(type)); } return map.get(type); } public static UnsharedFlyWeight getUnsharedFlyWeight(String type) { if (!unsharedMap.containsKey(type)) { unsharedMap.put(type, new UnsharedFlyWeight(type)); } return unsharedMap.get(type); } }
-
Client
:客戶端package com.self.designmode.flyweight; /** * 享元模式 * @author PJ_ZHANG * @create 2020-08-22 21:02 **/ public class Client { public static void main(String[] args) { FlyWeight flyWeight = FlyWeightFactory.getFlyWeight("新聞"); UnsharedFlyWeight unsharedFlyWeight = FlyWeightFactory.getUnsharedFlyWeight("特殊"); flyWeight.setUnsharedFlyWeight(unsharedFlyWeight); flyWeight.use(); System.out.println("----------------------------"); flyWeight = FlyWeightFactory.getFlyWeight("部落格"); unsharedFlyWeight = FlyWeightFactory.getUnsharedFlyWeight("特殊"); flyWeight.setUnsharedFlyWeight(unsharedFlyWeight); flyWeight.use(); System.out.println("----------------------------"); flyWeight = FlyWeightFactory.getFlyWeight("小程式"); unsharedFlyWeight = FlyWeightFactory.getUnsharedFlyWeight("特殊"); flyWeight.setUnsharedFlyWeight(unsharedFlyWeight); flyWeight.use(); System.out.println("----------------------------"); } }
13.6,注意事項及細節
- 當系統中存在大量物件,這些物件消耗大量記憶體,並且物件的狀態大部分可以外部化時,可以考慮使用享元模式
- 享元模式可以大大減少物件的建立,降低了程式記憶體的佔用,提高效率
- 享元模式提高了系統複雜度。需要分離出內部狀態和外部狀態,外部狀態具有固化特性,不會隨著內部狀態的改變而改變,這是使用享元模式需要注意的問題
- 享元模式的經典使用場景:String常量池,資料庫連線池,執行緒池
相關文章
- 設計模式系列13–享元模式設計模式
- C#設計模式(13)——享元模式C#設計模式
- 設計模式系列13--享元模式設計模式
- Java設計模式11——享元模式Java設計模式
- 設計模式----享元模式設計模式
- 設計模式-享元模式設計模式
- Java設計模式之(十一)——享元模式Java設計模式
- Java學設計模式之享元模式Java設計模式
- Java設計模式之七 —– 享元模式和代理模式Java設計模式
- 11.java設計模式之享元模式Java設計模式
- 設計模式之享元模式設計模式
- javascript設計模式享元模式JavaScript設計模式
- 設計模式(十七):享元模式設計模式
- 極簡設計模式-享元模式設計模式
- Python設計模式-享元模式Python設計模式
- iOS設計模式 (四)享元模式iOS設計模式
- 軟體設計模式————(享元模式)設計模式
- 好程式設計師分享java設計模式之享元模式程式設計師Java設計模式
- 好程式設計師精講 java設計模式—享元模式程式設計師Java設計模式
- 實驗13:享元模式模式
- C#設計模式之享元模式C#設計模式
- 通俗 Python 設計模式——享元模式Python設計模式
- 我學設計模式 之 享元模式設計模式
- Java進階篇設計模式之七 —– 享元模式和代理模式Java設計模式
- Java進階篇設計模式之七 ----- 享元模式和代理模式Java設計模式
- 《設計模式四》觀察、組合、享元模式設計模式
- 設計模式【10】-- 順便看看享元模式設計模式
- 設計模式 | 享元模式及典型應用設計模式
- 10、Python與設計模式–享元模式Python設計模式
- 設計模式(十六)----結構型模式之代理享元模式設計模式
- 每天一個設計模式之享元模式設計模式
- 軟體設計模式系列之十三——享元模式設計模式
- 設計模式--享元模式FlyWeight(結構型)設計模式
- C#設計模式系列:享元模式(Flyweight)C#設計模式
- 無廢話設計模式(9)結構型模式--享元模式設計模式
- 享元模式模式
- 12.享元模式設計思想模式
- Rust語言之GoF設計模式:Flyweight享元模式RustGo設計模式