首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C++ 代理模式實戰:Surrogate 類實現異構對象統一存儲與多態調用

     編輯:關於C語言

C++ 代理模式實戰:Surrogate 類實現異構對象統一存儲與多態調用

前言

當需要在同一容器中存儲不同派生類對象並統一調用介面時,代理/包裝類 是經典解決方案。本文通過「車輛管理系統」實例,展示 VehicleSurrogate 如何包裝 Vehicle 派生體系實現異構集合。

一、領域模型:車輛體系

1. 抽象基類 (介面)


class Vehicle {
public:
    virtual ~Vehicle() {}
    virtual void Weight() const = 0;
    virtual void Start() const = 0;
    virtual Vehicle* Clone() const = 0;  // 虛拷貝構造 (原型模式)
};

2. 具體實現


class SmallCar : public Vehicle {
public:
    void Weight() const override { std::cout << "小汽車重 400 斤\n"; }
    void Start() const override { std::cout << "小汽車啟動了\n"; }
    Vehicle* Clone() const override { return new SmallCar(*this); }
};

class BigBus : public Vehicle {
public:
    void Weight() const override { std::cout << "大汽車重 1.5 噸\n"; }
    void Start() const override { std::cout << "大汽車啟動了\n"; }
    Vehicle* Clone() const override { return new BigBus(*this); }
};

二、代理類:VehicleSurrogate


class VehicleSurrogate {
public:
    // 默認構造:空代理
    VehicleSurrogate() : m_Vehicle(nullptr) {}
    
    // 從基類引用構造:觸發虛拷貝
    VehicleSurrogate(const Vehicle& v) : m_Vehicle(v.Clone()) {}
    
    // 拷貝構造:深拷貝被代理對象
    VehicleSurrogate(const VehicleSurrogate& other) 
        : m_Vehicle(other.m_Vehicle ? other.m_Vehicle->Clone() : nullptr) {}
    
    // 複製賦值:複製並交換惯用法
    VehicleSurrogate& operator=(VehicleSurrogate other) {  // 參數傳值利用拷貝構造
        swap(other);
        return *this;
    }
    
    // 移動構造/賦值 (C++11)
    VehicleSurrogate(VehicleSurrogate&& other) noexcept : m_Vehicle(other.m_Vehicle) {
        other.m_Vehicle = nullptr;
    }
    VehicleSurrogate& operator=(VehicleSurrogate&& other) noexcept {
        if (this != &other) {
            delete m_Vehicle;
            m_Vehicle = other.m_Vehicle;
            other.m_Vehicle = nullptr;
        }
        return *this;
    }
    
    ~VehicleSurrogate() { delete m_Vehicle; }
    
    // 代理轉發
    void Weight() const { if (m_Vehicle) m_Vehicle->Weight(); }
    void Start() const { if (m_Vehicle) m_Vehicle->Start(); }
    
    // 交換支援
    void swap(VehicleSurrogate& other) noexcept {
        std::swap(m_Vehicle, other.m_Vehicle);
    }
    
private:
    Vehicle* m_Vehicle;  // 擁有被代理對象所有權
};

設計亮點

  1. 值語義:VehicleSurrogate 行為像值類型,可直接存入 std::vector
  2. 深拷貝:拷貝構造/賦值調用 Clone() 創建新對象,避免雙重釋放
  3. 複製並交換:賦值運算子參數傳值,利用拷貝構造 + swap 實現強異常安全
  4. 移動語義:C++11 移動操作零開銷轉移所有權
  5. 虛拷貝:Clone() 是原型模式應用,解決基類指標無法直接 new 的問題

三、客戶端使用示例


int main() {
    // 異構容器:直接存儲 VehicleSurrogate 值
    std::vector garage;
    
    garage.emplace_back(SmallCar());  // 就地構造
    garage.emplace_back(BigBus());
    
    std::cout << "=== 遍歷調用 ===\n";
    for (const auto& v : garage) {
        v.Start();
        v.Weight();
    }
    
    std::cout << "\n=== 複製容器 ===\n";
    std::vector garage2 = garage;  // 深拷貝整個車隊
    garage2[0].Start();  // 獨立副本
    
    return 0;
}

四、運行輸出

=== 遍歷調用 ===
小汽車啟動了
小汽車重 400 斤
大汽車啟動了
大汽車重 1.5 噸

=== 複製容器 ===
小汽車啟動了

五、與替代方案對比

方案優點缺點適用場景
基類指標容器 (vector)簡單、無額外封裝手動記憶體管理、拷貝容器需深拷貝、異常不安全單一擁有者、生命周期清晰
std::shared_ptr共享所有權、自動釋放控制塊開銷、循環引用風險、引用計數原子操作開銷多擁有者、共享所有權
std::unique_ptr + 移動零開銷、單一擁有權不可拷貝、容器拷貝需轉移獨占所有權、高性能
代理值類 (VehicleSurrogate)值語義、深拷貝自動、標準容器完美支援、異常安全每次拷貝分配記憶體、需實現 Clone()值語義集合、需拷貝語義、STL 算法兼容

六、擴展:支援狀態的代理

若被代理對象有狀態 (如里程數),代理類天然支援狀態隔離:


class Taxi : public Vehicle {
    int mileage_ = 0;
public:
    void Drive(int km) { mileage_ += km; }
    void Status() const { std::cout << "里程: " << mileage_ << "\n"; }
    Vehicle* Clone() const override { return new Taxi(*this); }  // 狀態隨對象拷貝
};

// 使用
VehicleSurrogate taxi1(Taxi());
taxi1.Drive(100);  // 需在 Surrogate 添加 Drive 轉發

VehicleSurrogate taxi2 = taxi1;  // 深拷貝,里程獨立
taxi2.Drive(50);
taxi1.Status();  // 100
taxi2.Status();  // 150

七、總結

VehicleSurrogate 模式通過值語義包裝多態對象,解決了「異構對象統一存儲 + 深拷貝語義 + STL 容器兼容」三大痛點。核心技術點:

  1. 虛拷貝 Clone() 實現運行時類型感知拷貝
  2. 控制塊模式管理被代理對象生命周期
  3. 複製並交換賦值運算子保證強異常安全
  4. 移動語義消除不必要的深拷貝

此模式廣泛應用於命令模式 (Command)、策略模式 (Strategy)、插件系統等需要「值語義多態」的場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved