iT邦幫忙

2023 iThome 鐵人賽

DAY 23
1
Software Development

深入淺出設計模式 - 使用 C++系列 第 23

[Day 23] 集中管理大量物件實例 - 蠅量模式 (Flyweight Pattern)

  • 分享至 

  • xImage
  •  

Intent

  • Aims to minimize memory usage or computational expenses by sharing as much as possible with related objects; it is used in scenarios where a large number of similar objects are needed

Motivation

  • 假設你正在開發一個森林模擬程序
  • 森林中的每棵樹都是一個對象 (Object),你可能有數百萬棵樹
  • 為每棵樹創建一個單獨的對象會消耗過多的記憶體
  • Flyweight 模式可以在所有樹之間共享樹對象的共同部分,從而減少記憶體占用

Applicability

當以下情況出現時,使用 Flyweight 模式:

  • 系統使用大量相似對象,存儲成本高
  • The object's majority of the state can be made extrinsic
  • 應用程序不依賴於對象身份

Structure

https://ithelp.ithome.com.tw/upload/images/20231005/20138643QcjzaDmL9g.png

Participants

Flyweight: 聲明一個接口,通過該接口享元可以接收並對外部狀態 (extrinsic states) 進行操作
ConcreteFlyweight: 實現享元接口並存儲內部狀態 (intrinsic state)
UnsharedConcreteFlyweight: 並非所有 Flyweight 子類都需要共享
FlyweightFactory: 創建和管理 Flyweight 對象
Client: 維護對 Flyweight 的引用,並計算或存儲 Flyweight 的外部狀態

補充: Intrinsic/Extrinsic States

  • Intrinsic State (內部狀態)

    • 內部狀態是對象內部的不變狀態,這些狀態是固有的,不會因外部環境的變化而變化
  • 特點

    • 不變性: 一旦創建,內部狀態就不會改變
    • 共享性: 內部狀態可以在多個實例之間共享
    • 獨立性: 內部狀態不依賴於外部狀態
  • 例子: 在森林模擬中,樹的種類(如松樹、橡樹等)可以作為內部狀態

  • Extrinsic State (外部狀態)

    • 外部狀態是對象與其環境相互作用的可變狀態
  • 特點

    • 可變性: 外部狀態可以改變
    • 非共享性: 通常,外部狀態是不能共享的
    • 依賴性: 外部狀態通常依賴於特定的情境
  • 例子: 在森林模擬中,樹的位置(x, y 座標)可以作為外部狀態

  • 總結

    • **分離與管理:**通過分離內部和外部狀態來實現對象共享。內部狀態由 Flyweight 對象管理,而外部狀態由 Client 管理
    • 記憶體優化: 通過共享具有相同內部狀態的對象,能夠顯著減少記憶體使用

Collaborations

  • 客戶端對象不直接實例化 ConcreteFlyweight 對象,他們通過 FlyweightFactory 檢索 (Retrieve) 這些對象
  • FlyweightFactory 對象創建和管理 ConcreteFlyweight 對象

Consequences

優點

  • 顯著的記憶體節省
  • 由於對象重用,性能得到提升 (Improved performance due to object reuse)

缺點

  • 由於內部和外部狀態的分離,複雜性增加
  • 如果沒有仔細處理,線程安全 (Thread safety) 可能會受到影響

Implementation (範例: Led 控制)

  • 在嵌入式軟體環境中,記憶體和計算資源通常是有限的。因此,Flyweight Pattern 可以是一個非常有用的設計模式
  • 假設我們正在開發一個用於控制多個 LED 燈的嵌入式系統。每個 LED 燈可以是紅色、綠色或藍色,並且可以在不同的亮度級別上運行
// Flyweight Interface
class LED {
public:
    virtual void display(int brightness) = 0;
};

// Concrete Flyweight
class ConcreteLED : public LED {
private:
    std::string color;
public:
    ConcreteLED(std::string color) : color(color) {}
    void display(int brightness) override {
        std::cout << "Displaying " << color << " LED with brightness: " << brightness << std::endl;
    }
};

// Flyweight Factory
class LEDFactory {
private:
    std::map<std::string, LED*> ledMap;
public:
    LED* getLED(std::string color) {
        // map 原先不存在這個顏色的 LED 的話,new 1 個 ConcreteLED 存進去 map
        if (ledMap.find(color) == ledMap.end()) {
            ledMap[color] = new ConcreteLED(color);
        }
        
        return ledMap[color];
    }
};

int main() {
    LEDFactory factory;

    // Client code
    LED* redLED = factory.getLED("Red");
    redLED->display(10);

    LED* greenLED = factory.getLED("Green");
    greenLED->display(20);

    LED* anotherRedLED = factory.getLED("Red");
    anotherRedLED->display(15);
}

Known Uses

  • Text editors for character styling
  • 圖形系統用於渲染形狀 (rendering shapes)
  • Database connection pooling

Related Patterns

Composite Pattern (組合模式): Often used with Flyweight for a hierarchical structure
Factory Method Pattern (工廠方法模式): Useful for creating flyweight objects

Reference

  1. https://refactoring.guru/design-patterns/flyweight

上一篇
[Day 22] 為請求創建一條處理鍊 - 責任鍊設計模式 (Chain of Responsibility Pattern)
下一篇
[Day 24] 以類別來表達文法規則 -解譯器模式 (Interpreter Pattern)
系列文
深入淺出設計模式 - 使用 C++37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言