iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0
Software Development

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

[Day 27] 複製複雜已知物件 - 原型模式 (Protorype Pattern)

  • 分享至 

  • xImage
  •  

(待改進...)

簡介

  • 原型模式用於創建對象的複製。這種模式主要用於避免創建對象的成本和資源消耗,特別是當一個對象需要經過時間消耗的初始化過程時

Applicability

  • 當創建單個對象的成本過高或複雜時
  • 當需要保留對象的狀態,並且後續需要基於這些狀態創建新對象時

基本概念

  • 原型 (Prototype): 這是一個實現了自我複製 (self-copying) 功能的對象
  • 客戶端 (Client): 使用原型實例的對象

Consequences

優點

  • 高效: 避免了手動創建對象所需的初始化成本
  • 靈活: 允許在運行時動態地創建對象

缺點

  • 深拷貝與淺拷貝問題: 需要注意對象內部的複製細節
  • 維護複雜性: 當對象有多個版本或配置時

[補充] 深拷貝 (Deep Copy) vs. 淺拷貝 (Shallow Copy)

淺拷貝

  • 僅僅是對基本數據類型 (如整數、浮點數等) 的拷貝,以及對指針變量的地址拷貝,而不會拷貝指針指向的實際對象
class ShallowCopyPrototype : public Prototype {
public:
    int* data;

    ShallowCopyPrototype() {
        data = new int;
    }

    std::unique_ptr<Prototype> clone() const override {
        auto cloneObj = std::make_unique<ShallowCopyPrototype>();
        cloneObj->data = this->data;  // 只拷貝指針,不拷貝指針指向的數據
        return cloneObj;
    }
};

缺點

  • 容易引發資源管理問題,例如兩個對象可能會共享相同的資源
  • 不適用於需要獨立副本的場景

深拷貝

  • 不僅拷貝對象的基本類型,還會遞迴地拷貝對象中的所有後續對象。換句話說,它會創建一個完全獨立的對象副本
class DeepCopyPrototype : public Prototype {
public:
    int* data;

    DeepCopyPrototype() {
        data = new int;
    }

    std::unique_ptr<Prototype> clone() const override {
        auto cloneObj = std::make_unique<DeepCopyPrototype>();
        cloneObj->data = new int;  // 創建新的內存
        *(cloneObj->data) = *(this->data);  // 拷貝數據
        return cloneObj;
    }
};

優點

  • 創建了完全獨立的對象副本
  • 避免了資源共享的問題

[補充]: 拷貝構造函數 (Copy Constructor) vs. 拷貝賦值 (Copy Assignment)

拷貝構造函數 (Copy Constructor)

  • 是一種特殊的構造函數,用於創建一個新對象,並將現有對象的狀態 (即成員變量的值) 複製到新對象中。拷貝構造函數的主要目的是確保深拷貝和淺拷貝行為得以正確實現
  • 語法
    ClassName(const ClassName& other);
    
  • 觸發時機: 拷貝構造函數會在以下幾種情況下被調用
    • 初始化一個新對象: ClassName obj1 = obj2
    • 作為函數參數傳遞: 當一個對象以值的形式傳遞給函數
    • 作為函數返回值:當一個對象以值的形式從函數返回
    • 手動調用: 使用 new 關鍵字或其他方式手動調用
  • 範例
    class MyClass {
    private:
        int* data;
    public:
        // 普通構造函數
        MyClass(int value) {
            data = new int(value);
        }
    
        // 拷貝構造函數(深拷貝)
        MyClass(const MyClass& other) {
            data = new int(*other.data);
        }
    
        // 解構函數
        ~MyClass() {
            delete data;
        }
    
        void show() {
            std::cout << *data << std::endl;
        }
    };
    
    int main() {
        MyClass obj1(42);
        MyClass obj2 = obj1;  // 調用拷貝構造函數
    
        obj1.show();  // 輸出:42
        obj2.show();  // 輸出:42
    }
    

拷貝賦值 (Copy Assignment)

  • 觸發時機: 與賦值運算符相同,但通常會涉及資源的拷貝
  • 區別: 拷貝賦值是賦值運算符的一種特殊形式,通常會涉及深拷貝

範例: Deep-copy Prototype

// 原型基類
class Prototype {
public:
    virtual std::unique_ptr<Prototype> clone() const = 0;
    virtual void operation() const = 0;
};

// 具體原型
class ConcretePrototype : public Prototype {
public:
    std::unique_ptr<Prototype> clone() const override {
        return std::make_unique<ConcretePrototype>(*this);
    }

    void operation() const override {
        std::cout << "ConcretePrototype operation" << std::endl;
    }
};

int main() {
    std::unique_ptr<Prototype> prototype = std::make_unique<ConcretePrototype>();
    prototype->operation();

    std::unique_ptr<Prototype> clonedPrototype = prototype->clone();
    clonedPrototype->operation();
}

Reference

  1. https://medium.com/bucketing/creational-patterns-prototype-pattern-eb6e3c14f1b2
  2. https://refactoring.guru/design-patterns/prototype

上一篇
[Day 26] 儲存系統的重要狀態 — 備忘錄模式 (Memento Pattern)
下一篇
[Day 28] 不修改對象並為其添加操作 - 訪問者模式 (Visitor Pattern)
系列文
深入淺出設計模式 - 使用 C++37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言