Java_設計模式之享元模式

来源:https://www.cnblogs.com/dongxiucai/archive/2018/08/11/9460069.html
-Advertisement-
Play Games

1、關於享元模式 享元模式有點類似於單例模式,都是只生成一個對象被共用使用。享元模式主要目的就是讓多個對象實現共用,減少不會要額記憶體消耗,將多個對同一對象的訪問集中起來,不必為每個訪問者創建一個單獨的對象,以此來降低記憶體的消耗。 2、享元模式結構圖 因為享元模式結構比較複雜,一般結合工廠模式一起使用 ...


1、關於享元模式

  享元模式有點類似於單例模式,都是只生成一個對象被共用使用。享元模式主要目的就是讓多個對象實現共用,減少不會要額記憶體消耗,將多個對同一對象的訪問集中起來,不必為每個訪問者創建一個單獨的對象,以此來降低記憶體的消耗。

2、享元模式結構圖

  因為享元模式結構比較複雜,一般結合工廠模式一起使用,在它的結構圖中包含了一個享元工廠類。

  在享元模式結構圖中包含如下幾個角色:

    Flyweight(抽象享元類):通常是一個介面或抽象類,在抽象享元類中聲明瞭具體享元類公共的方法,這些方法可以向外界提供享元對象的內部數據(內部狀態),同時也可以通過這些方法來設置外部數據(外部狀態)。

    ConcreteFlyweight(具體享元類):它實現了抽象享元類,其實例稱為享元對象;在具體享元類中為內部狀態提供了存儲空間。通常我們可以結合單例模式來設計具體享元類,為每一個具體享元類提供唯一的享元對象。

    UnsharedConcreteFlyweight(非共用具體享元類):並不是所有的抽象享元類的子類都需要被共用,不能被共用的子類可設計為非共用具體享元類;當需要一個非共用具體享元類的對象時可以直接通過實例化創建。

     FlyweightFactory(享元工廠類):享元工廠類用於創建並管理享元對象,它針對抽象享元類編程,將各種類型的具體享元對象存儲在一個享元池中,享元池一般設計為一個存儲“鍵值對”的集合(也可以是其他類型的集合),可以結合工廠模式進行設計;當用戶請求一個具體享元對象時,享元工廠提供一個存儲在享元池中已創建的實例或者創建一個新的實例(如果不存在的話),返回新創建的實例並將其存儲在享元池中。

3、享元模式的實現    

  在享元模式中引入了享元工廠類,享元工廠類的作用在於提供一個用於存儲享元對象的享元池,當用戶需要對象時,首先從享元池中獲取,如果享元池中不存在,則創建一個新的享元對象返回給用戶,併在享元池中保存該新增對象。

  接下來,實現一個登陸的享元模式。

  1、用戶類

 1 /**
 2  * 用戶類
 3  * @author 董秀才
 4  *
 5  */
 6 public class User {
 7     private String username; // 用戶名
 8     private String password; // 密碼
 9     
10     public User(String username,String password) {
11         this.username = username;
12         this.password = password;
13     }
14 
15     public String getUsername() {
16         return username;
17     }
18 
19     public void setUsername(String username) {
20         this.username = username;
21     }
22 
23     public String getPassword() {
24         return password;
25     }
26 
27     public void setPassword(String password) {
28         this.password = password;
29     }
30 }

  2、抽象的登陸者(抽象享元類)

 1 /**
 2  * 登陸者--抽象享元類
 3  * @author 董秀才
 4  *
 5  */
 6 public abstract class Loginer {
 7     
 8     //登陸--享元類公共方法
 9     public abstract void login(User user);
10     
11 }

  3、具體的登陸者(具體享元類)

 1 /**
 2  * 具體享元類
 3  * @author 董秀才
 4  *
 5  */
 6 public class ConcreteLoginer extends Loginer{
 7 
 8     // 登陸者憑證
 9     private String loginerKey = "";
10     public ConcreteLoginer(String loginerKey) {
11         this.loginerKey = loginerKey;
12     }
13     
14     @Override
15     public void login(User user) {
16         System.out.println("登陸者憑證:" + this.loginerKey+",用戶名:" + user.getUsername() + ",密碼:" + user.getPassword());
17     }
18     
19 }

  4、具體登陸者的工廠類(享元工廠類)

 1 /**
 2  * 享元工廠類
 3  * @author 董秀才
 4  *
 5  */
 6 public class ConcreteLoginerFactory {
 7     
 8     // map充當對象享元池
 9     private static Map<String,ConcreteLoginer> loginerMap = new  HashMap<String, ConcreteLoginer>();
10     
11     public static ConcreteLoginer getConcreteLoginer(String key) {
12         // 從享元池中拿  登陸者對象
13         ConcreteLoginer concreteLoginer = loginerMap.get(key);
14         // 如果享元池中沒有此對象 
15         if(concreteLoginer == null) {
16             // 創建對象
17             concreteLoginer = new ConcreteLoginer(key);
18             // 存到享元池中
19             loginerMap.put(key, concreteLoginer);
20         }
21         // 返回對象
22         return concreteLoginer;
23     }
24     
25     
26     // 返回享元池對象數量
27     public static int getSize() {
28         return loginerMap.size();
29     }
30 }

  5、測試類 

 1 /**
 2 * 博客測試類
 3 * @author 董秀才
 4 *
 5 */
 6 public class MainTest {
 7 
 8 public static void main(String[] args) {
 9 // 去工廠拿對象
10 ConcreteLoginer concreteLoginer_1 = ConcreteLoginerFactory.getConcreteLoginer("csdn");
11 concreteLoginer_1.login(new User("董秀才","123456"));
12 
13 ConcreteLoginer concreteLoginer_2 = ConcreteLoginerFactory.getConcreteLoginer("csdn");
14 concreteLoginer_2.login(new User("董秀才","123456"));
15 
16 ConcreteLoginer concreteLoginer_3 = ConcreteLoginerFactory.getConcreteLoginer("csdn");
17 concreteLoginer_3.login(new User("董秀才","123456"));
18 
19 // 測試是否是同一個對象
20 System.out.println("是否是同一個對象:" + ((concreteLoginer_1==concreteLoginer_2)&&(concreteLoginer_2 == concreteLoginer_3)));
21 
22 
23 // 第二登陸者
24 ConcreteLoginer concreteLoginer_4 = ConcreteLoginerFactory.getConcreteLoginer("博客園");
25 concreteLoginer_4.login(new User("董才才","654321"));
26 
27 ConcreteLoginer concreteLoginer_5 = ConcreteLoginerFactory.getConcreteLoginer("博客園");
28 concreteLoginer_5.login(new User("董才才","654321"));
29 
30 ConcreteLoginer concreteLoginer_6 = ConcreteLoginerFactory.getConcreteLoginer("博客園");
31 concreteLoginer_6.login(new User("董才才","654321"));
32 
33 System.out.println("是否是同一個對象:" + ((concreteLoginer_4==concreteLoginer_5)&&(concreteLoginer_5 == concreteLoginer_6)));
34 // 工廠類中享元池中對象數量
35 System.out.println("享元池size:" + ConcreteLoginerFactory.getSize());
36 }
37 
38 }

 

  6、運行結果

  

4、總結

  從上面代碼和運行結果這可以看到,同一個登陸者登陸時是  "享"  用同一個登陸者對象。在享元對象池中只有兩個對象。

  享元模式優點

  享元模式的外部狀態相對獨立,使得對象可以在不同的環境中被覆用(共用對象可以適應不同的外部環境)

  享元模式可共用相同或相似的細粒度對象,從而減少了記憶體消耗,同時降低了對象創建與垃圾回收的開銷

  享元模式缺點

  外部狀態由客戶端保存,共用對象讀取外部狀態的開銷可能比較大

  享元模式要求將內部狀態與外部狀態分離,這使得程式的邏輯複雜化,同時也增加了狀態維護成本


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.不可改變的原始值(棧數據)(五個) 數字(number),字元串(string),布爾值(boolean),undefined,null 其中;undefined是未定義的意思,而null是空的意思,他們倆的區別在於,null有值,不過這個值是空值,而undefined是未定義,完全沒有值的意思 ...
  • 遞歸演算法: 優點:代碼簡潔、清晰,並且容易驗證正確性。 缺點: 1、它的運行需要較多次數的函數調用,如果調用層數比較深,每次都要創建新的變數,需要增加額外的堆棧處理,會對執行效率有一定影響,占用過多的記憶體資源。 2、遞歸演算法解題的運行效率較低。在遞歸調用的過程中系統為每一層的返回點、局部變數等開闢了 ...
  • 1、DOM0級事件和DOM2級事件 DOM 0級事件是元素內的一個私有屬性:div.onclick = function () {},對一個私有屬性賦值(在該事件上綁定一個方法)。由此可知DOM 0級事件只能給元素的某一個行為綁定一次方法,第二次綁定會把前面的覆蓋掉。 DOM 2級事件是讓DOM元素 ...
  • 一.Yeoman是什麼 是現代化前端項目的腳手架工具,用於生成包含指定框架結構的工程化目錄結構。它是整個前端自動化工廠的第一站。 從個人使用者的角度來看, 的地位有些雞肋,因為流行框架自帶的 工具都能夠自動生成官方推薦的目錄結構,而且一個項目持續少則幾個月多則幾年,而項目的初始化結構目錄在此期間只需 ...
  • CSS選擇器總結: (這些表是一張圖片^_^) 看底部 完整思維導圖圖片和表格的下載地址:https://download.csdn.net/download/denlnyyr/10597820 (我不想選擇要積分幣下載的,但那裡最低必須選擇1個積分……) 參考文獻: https://baike.b ...
  • 看到一個知識點,比如說給一個 url參數,讓其解析裡面的各個參數,以前我都是通過字元串分割來實現的。但是通過這樣的方式比較麻煩,而且操作字元串容易出錯。今天看到了一個更有效更快速的方式,就是通過對象來解析的。 比如我們的url是:https://www.baidu.com:8080/aaa/1.ht ...
  • 先附一張官網上的vue實例的生命周期圖,每個Vue實例在被創建的時候都需要經過一系列的初始化過程,例如需要設置數據監聽,編譯模板,將實例掛載到DOM併在數據變化時更新DOM等。同時在這個過程中也會運行一些叫做生命周期鉤子的函數(回調函數),這給了用戶在不同階段添加自己代碼的機會。 1、vue的生命周 ...
  • 為什麼要動態載入呢?而不是一次性載入呢? 一次性?你能保證你拿的內容不多,那從性能方面說還是OK的。否則,就該什麼時候用,就什麼時候取。 得出這想法,源於前幾天上班趕產品的故事: A組件是父親,B組件是A組件的孩子。剛剛,我在A組件里直接載入B組件。 編譯居然用了將近一分半鐘,我都還沒加其他C孩子, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...