【再談設計模式】享元模式~對象共享的優化妙手

一、引言

????????在軟件開發過程中,我們常常面臨著創建大量細粒度對象的情況,這可能會導致內存占用過高、性能下降等問題。享元模式(Flyweight Pattern)就像是一位空間管理大師,它能夠在不影響功能的前提下,有效地減少對象的數量,從而優化系統資源的使用。

二、定義與描述

????????享元模式是一種結構型設計模式,它主要用于通過共享盡可能多的相似對象來減少內存使用和提高性能。其核心思想是將對象的狀態分為內部狀態(intrinsic state)和外部狀態(extrinsic state)。內部狀態是對象可共享的部分,它不會隨環境的改變而改變;外部狀態則是隨環境變化而變化的部分,不能被共享。

三、抽象背景

????????假設我們正在開發一個游戲,游戲中有許多相同類型的怪物,這些怪物可能只有一些屬性(如生命值、攻擊力等)的差異。如果我們為每個怪物都創建一個獨立的對象,那么隨著怪物數量的增加,內存的消耗將變得非常大。享元模式就可以用來解決這個問題,將怪物的通用屬性(如外觀、基本行為等內部狀態)進行共享,而將每個怪物特有的屬性(如當前生命值、當前攻擊力等外部狀態)單獨處理。

四、適用場景與現實問題解決

  • 圖形繪制系統
    • 在圖形繪制系統中,可能需要繪制大量相同類型的圖形,如圓形、矩形等。這些圖形的形狀(內部狀態)是固定的,但它們的位置、顏色(外部狀態)可能不同。通過享元模式,可以共享圖形的形狀對象,減少內存占用。

  • 文檔編輯器中的字符處理
    • 文檔編輯器中有大量的字符,每個字符的字體樣式、大小等屬性可能不同,但字符的基本形狀(內部狀態)是相同的。享元模式可以用來共享字符的基本形狀對象。

五、享元模式的現實生活的例子

  • 汽車租賃公司
    • 汽車租賃公司有多種類型的汽車可供租賃,如轎車、SUV等。每一種類型的汽車(內部狀態)是固定的,包括車型、座位數等。而汽車的顏色、當前里程數(外部狀態)是隨每一次租賃而變化的。租賃公司可以將相同類型的汽車看作是享元對象,共享汽車的基本信息,從而更好地管理車輛資源。

  • 咖啡店的咖啡杯
    • 咖啡店有不同種類的咖啡杯,如拿鐵杯、卡布奇諾杯等。杯子的形狀(內部狀態)是固定的,但是杯子里咖啡的量、是否加糖(外部狀態)是不同的。咖啡店可以將相同類型的杯子看作享元對象,共享杯子的基本形狀信息。

六、初衷與問題解決

????????初衷是為了減少內存中對象的數量,提高系統的性能和資源利用率。通過共享內部狀態,避免了創建大量重復的對象,從而解決了因對象數量過多導致的內存占用過大和性能下降的問題。

七、代碼示例

Java示例

類圖:

  • FlyweightFactory?類有一個私有屬性?flyweights(類型為?Map<String, Flyweight>)用于存儲享元對象,并且有?getFlyweight?方法,根據傳入的?key?來獲取或創建具體的享元對象。
  • Flyweight?是抽象類,有受保護的屬性?key,構造方法以及抽象方法?operation,定義了享元對象的基本結構和行為規范。
  • ConcreteFlyweight?類繼承自?Flyweight?類,實現了自己的構造方法,并覆寫了?operation?方法,用于提供具體的享元行為實現。

流程圖:

????????首先創建?FlyweightFactory?對象,然后兩次調用?getFlyweight?方法來獲取享元對象(第二次調用時會復用第一次創建的對象,因為已經存在對應?key?的對象了),最后分別調用獲取到的享元對象的?operation?方法來執行具體操作。?

代碼:

import java.util.HashMap;
import java.util.Map;// 享元工廠類
class FlyweightFactory {private Map<String, Flyweight> flyweights = new HashMap<>();public Flyweight getFlyweight(String key) {if (!flyweights.containsKey(key)) {flyweights.put(key, new ConcreteFlyweight(key));}return flyweights.get(key);}
}// 抽象享元類
abstract class Flyweight {protected String key;public Flyweight(String key) {this.key = key;}abstract void operation();
}// 具體享元類
class ConcreteFlyweight extends Flyweight {public ConcreteFlyweight(String key) {super(key);}@Overridevoid operation() {System.out.println("具體享元 " + key + " 被調用");}
}public class Main {public static void main(String[] args) {FlyweightFactory factory = new FlyweightFactory();Flyweight flyweight1 = factory.getFlyweight("A");Flyweight flyweight2 = factory.getFlyweight("A");flyweight1.operation();flyweight2.operation();}
}

C++示例

#include <iostream>
#include <unordered_map>// 抽象享元類
class Flyweight {
public:virtual void operation() = 0;virtual ~Flyweight() {}
};// 具體享元類
class ConcreteFlyweight : public Flyweight {
private:std::string key;
public:ConcreteFlyweight(std::string key) : key(key) {}void operation() override {std::cout << "具體享元 " << key << " 被調用" << std::endl;}
};// 享元工廠類
class FlyweightFactory {
private:std::unordered_map<std::string, Flyweight*> flyweights;
public:Flyweight* getFlyweight(std::string key) {if (flyweights.find(key) == flyweights.end()) {flyweights[key] = new ConcreteFlyweight(key);}return flyweights[key];}~FlyweightFactory() {for (auto it : flyweights) {delete it.second;}}
};int main() {FlyweightFactory factory;Flyweight* flyweight1 = factory.getFlyweight("A");Flyweight* flyweight2 = factory.getFlyweight("A");flyweight1->operation();flyweight2->operation();return 0;
}

Python示例

class FlyweightFactory:def __init__(self):self.flyweights = {}def get_flyweight(self, key):if key not in self.flyweights:self.flyweights[key] = ConcreteFlyweight(key)return self.flyweights[key]class Flyweight:def __init__(self, key):self.key = keydef operation(self):passclass ConcreteFlyweight(Flyweight):def operation(self):print(f"具體享元 {self.key} 被調用")if __name__ == "__main__":factory = FlyweightFactory()flyweight1 = factory.get_flyweight("A")flyweight2 = factory.get_flyweight("A")flyweight1.operation()flyweight2.operation()

Go示例

package mainimport ("fmt"
)// 抽象享元接口
type Flyweight interface {operation()
}// 具體享元結構體
type ConcreteFlyweight struct {key string
}func (cf *ConcreteFlyweight) operation() {fmt.Printf("具體享元 %s 被調用\n", cf.key)
}// 享元工廠結構體
type FlyweightFactory struct {flyweights map[string]Flyweight
}func NewFlyweightFactory() *FlyweightFactory {return &FlyweightFactory{flyweights: make(map[string]Flyweight),}
}func (ff *FlyweightFactory) getFlyweight(key string) Flyweight {if _, ok := ff.flyweights[key];!ok {ff.flyweights[key] = &ConcreteFlyweight{key}}return ff.flyweights[key]
}func main() {factory := NewFlyweightFactory()flyweight1 := factory.getFlyweight("A")flyweight2 := factory.getFlyweight("A")flyweight1.operation()flyweight2.operation()
}

八、享元模式的優缺點

  • 優點

    • 減少內存占用:通過共享對象,大大減少了創建對象所需的內存空間,特別是在處理大量相似對象時效果顯著。
    • 提高性能:減少了對象的創建和銷毀操作,從而提高了系統的運行速度。
    • 易于維護:將對象的內部狀態和外部狀態分離,使得代碼結構更加清晰,易于理解和維護。
  • 缺點

    • 增加復雜性:需要額外的代碼來管理享元對象的創建、共享和維護,這可能會增加系統的復雜性。
    • 外部狀態管理:外部狀態的處理需要額外的設計考慮,如果處理不當可能會導致邏輯混亂。

九、享元模式的升級版

????????一種常見的升級版是組合享元模式(Composite Flyweight Pattern)。在這種模式下,享元對象可以組合成更復雜的結構。例如,在圖形繪制系統中,不僅可以共享單個圖形(如圓形、矩形)的享元對象,還可以將這些享元對象組合成更復雜的圖形(如由多個圓形和矩形組成的復雜圖案),而這個復雜圖案本身也可以作為一個享元對象被共享。這樣可以進一步提高系統的靈活性和資源利用率。

思維導圖:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64148.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64148.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64148.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Milvus×EasyAi:如何用java從零搭建人臉識別應用

如何從零搭建一個人臉識別應用&#xff1f;不妨試試原生Java人工智能算法&#xff1a;EasyAi Milvus 的組合拳。 本文將使用到的軟件和工具包括&#xff1a; EasyAi&#xff1a;人臉特征向量提取Milvus&#xff1a;向量數據庫用于高效存儲和檢索數據。 01. EasyAi&#xff1a;…

NS3學習——tcpVegas算法代碼詳解(2)

NS3學習——tcpVegas算法代碼詳解&#xff08;1&#xff09;-CSDN博客 目錄 4.TcpVegas類中成員函數 (5) CongestionStateSet函數 (6) IncreaseWindow函數 1.檢查是否啟用 Vgas 2.判斷是否完成了一個“Vegas 周期” 2.1--if&#xff1a;判斷RTT樣本數量是否足夠 2.2--e…

GitLab 將停止為中國區用戶提供服務,60天遷移期如何應對? | LeetTalk Daily

“LeetTalk Daily”&#xff0c;每日科技前沿&#xff0c;由LeetTools AI精心篩選&#xff0c;為您帶來最新鮮、最具洞察力的科技新聞。 GitLab作為一個廣受歡迎的開源代碼托管平臺&#xff0c;近期宣布將停止服務中國大陸、澳門和香港地區的用戶提供服務。根據官方通知&#x…

華為實訓課筆記 2024 1223-1224

華為實訓 12/2312/24 12/23 [Huawei]stp enable --開啟STP display stp brief --查詢STP MSTID Port Role STP State Protection 實例ID 端口 端口角色 端口狀態 是否開啟保護[Huawei]display stp vlan xxxx --查詢制定vlan的生成樹計算結…

企業數字化轉型中如何區分“IT投入”和“業務投入”

在數字化轉型的浪潮中&#xff0c;企業往往面臨一個關鍵問題&#xff1a;如何區分“IT投入”和“業務投入”&#xff1f;在很多企業中&#xff0c;這兩個概念往往被混淆&#xff0c;不少公司甚至認為“數字化轉型”就是“IT的事情”&#xff0c;但實際上&#xff0c;它們之間有…

【Spring AI】Spring AI Alibaba的簡單使用

提示&#xff1a;文章最后有詳細的參考文檔。 前提條件 SpringBoot版本為3.x以上JDK為17以上申請api-key&#xff0c;地址&#xff1a;百煉平臺 引入依賴 說明&#xff1a;我的springboot版本為3.2.4&#xff0c;spring-ai-alibaba-starter版本為1.0.0-M2.1(對應spring-ai版本…

《Java源力物語》-3.空值獵手

~犬&#x1f4f0;余~ “我欲賤而貴&#xff0c;愚而智&#xff0c;貧而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯學乎” \quad 夜色漸深&#xff0c;在一處偏僻小徑上&#xff0c;月光透過濃密的源力云層&#xff0c;在地面上投下斑駁的光影。String正獨自練習著剛從…

科技云報到:人工智能時代“三大件”:生成式AI、數據、云服務

科技云報到原創。 就像自行車、手表和縫紉機是工業時代的“三大件”。生成式AI、數據、云服務正在成為智能時代的“新三大件”。加之全球人工智能新基建加速建設&#xff0c;成為了人類社會數字化遷徙的助推劑&#xff0c;讓新三大件之間的耦合越來越緊密。從物理世界到數字世…

hiprint結合vue2項目實現靜默打印詳細使用步驟

代碼地址是&#xff1a;vue-plugin-hiprint: hiprint for Vue2/Vue3 ?打印、打印設計、可視化設計器、報表設計、元素編輯、可視化打印編輯 本地安裝包地址&#xff1a;electron-hiprint 發行版 - Gitee.com 1、先安裝hipint安裝包在本地 2、項目運行npm&#xff08;socket.…

CUDA各種內存和使用方法

文章目錄 1、全局內存2、局部內存3、共享內存3.1 靜態共享內存3.2 動態共享內存 4、紋理內存5、常量內存6、寄存器內存7、用CUDA運行時API函數查詢設備CUDA 錯誤檢測 1、全局內存 特點&#xff1a;容量最大&#xff0c;訪問延時最大&#xff0c;所有線程都可以訪問。 線性內存…

Chapter 03 復合數據類型-1

1.列表 Python內置的一種有序、可變的序列數據類型&#xff1b; 列表的定義&#xff1a; [ ]括起來的逗號分隔的多個元素組成的序列 列表對象的創建&#xff1a; &#xff08;1&#xff09;直接賦值 >>> list1 []#創建一個空列表賦值給list1 >>> list…

【后端】LNMP環境搭建

長期更新各種好文&#xff0c;建議關注收藏&#xff01; 本文近期更新完畢。 LNMPlinuxnginxmysqlphp 需要的資源 linux服務器 web服務軟件nginx 對應的語言編譯器代碼文件 數據庫mysql安裝 tar.gz包或者命令行安裝 進入root&#xff1a; sodu 或su mkdir path/{server,soft}…

基于PyQt5的UI界面開發——多界面切換

介紹 最初&#xff0c;因為課設的緣故&#xff0c;我只是想做一個通過按鍵進行切面切換而已&#xff0c;但是我看網上資料里面僅是語焉不詳&#xff0c;讓我困惑的很&#xff0c;但后面我通過摸索才發現這件事實在是太簡單了&#xff0c;因此我想要記錄下來。 本博客將介紹如…

操作002:HelloWorld

文章目錄 操作002&#xff1a;HelloWorld一、目標二、具體操作1、創建Java工程①消息發送端&#xff08;生產者&#xff09;②消息接收端&#xff08;消費者&#xff09;③添加依賴 2、發送消息①Java代碼②查看效果 3、接收消息①Java代碼②控制臺打印③查看后臺管理界面 操作…

機器視覺檢測相機基礎知識 | 顏色 | 光源 | 鏡頭 | 分辨率 / 精度 / 公差

注&#xff1a;本文為 “keyence 視覺沙龍中機器視覺檢測基礎知識” 文章合輯。 機器視覺檢測基礎知識&#xff08;一&#xff09;顏色篇 視覺檢測硬件構成的基本部分包括&#xff1a;處理器、相機、鏡頭、光源。 其中&#xff0c;和光源相關的最重要的兩個參數就是光源顏色和…

【每日學點鴻蒙知識】壓力測試、Web組件攔截器、nfc開關狀態、定位能力、rn支持的三方庫

1、HarmonyOS的wukong 支持運行python腳本進行壓力或者常規測試嗎&#xff1f; Python腳本調用hdc命令&#xff0c;執行hdc shell wukong XXXwukong只支持穩定性壓測&#xff0c;普通測試建議使用arkxtest測試框架 2、Web組件頁面內跳轉時自定義WebHeader問題&#xff1f; 如…

GDPU Vue前端框架開發 期末賽道出勇士篇(更新ing)

記住&#xff0c;年底陪你跨年的不會僅是方便面跟你的閨蜜&#xff0c;還有孑的筆記。 選擇題 1.下列選項用于設置Vue.js頁面視圖的元素是&#xff08;&#xff09;。 A. Template B. script C. style D. title 2.下列選項中能夠定義Vuejs根實例對象的元素是&#xff08;&…

Flutter開發HarmonyOS 鴻蒙App的好處、能力以及把Flutter項目打包成鴻蒙應用

Flutter開發HarmonyOS的好處&#xff1a; Flutter是谷歌公司開發的一款開源、免費的UI框架&#xff0c;可以讓我們快速的在Android和iOS上構建高質量App。它最大的特點就是跨平臺、以及高性能。 目前 Flutter 已經支持 iOS、Android、Web、Windows、macOS、Linux 的跨平臺開發…

Effective C++ 條款 17:以獨立語句將 `newed` 對象置入智能指針

文章目錄 條款 17&#xff1a;以獨立語句將 newed 對象置入智能指針核心思想示例代碼錯誤用法分析推薦設計總結 條款 17&#xff1a;以獨立語句將 newed 對象置入智能指針 核心思想 問題背景 如果在將 newed 對象傳遞給智能指針時&#xff0c;包含了復雜的表達式&#xff0c;一…

【體驗官招募】SoFlu - JavaAI 開發助手:開啟智能開發新時代

你是否有過這樣的經歷&#xff1f;在深夜的辦公室里&#xff0c;面對緊急的 Java 項目&#xff0c;看著厚厚的需求文檔&#xff0c;你是否感到無從下手&#xff1f; 當你嘗試理解客戶那些復雜又模糊的需求時&#xff0c;是否會因為要和產品經理反復溝通確認每一個細節而感到厭…