注意:復現代碼時,確保 VS2022 使用 C++17/20 標準以支持現代特性。
分步驟構造復雜對象,實現靈活裝配
1. 模式定義與用途
核心目標:將復雜對象的構建過程分離,使得同樣的構建步驟可以創建不同的表示形式。
常見場景:
- 創建包含多個組件的復雜對象(如游戲角色、文檔格式)
- 需要逐步構造對象,并支持不同配置選項
- 避免構造函數參數爆炸(尤其是可選參數眾多時)
2. 模式結構解析
Builder
:定義構造步驟的抽象接口(如buildHead()
,buildBody()
)ConcreteBuilder
:實現具體構造邏輯,提供獲取結果的接口Director
:控制構造流程(可選,可讓客戶端直接操作Builder)Product
:最終構造的復雜對象
3. 現代 C++ 實現示例:游戲角色構造
3.1 基礎實現
#include <iostream>
#include <memory>
#include <string>// 產品:游戲角色
class GameCharacter {
public:void setHead(const std::string& head) { head_ = head; }void setBody(const std::string& body) { body_ = body; }void setWeapon(const std::string& weapon) { weapon_ = weapon; }void describe() const {std::cout << "Character: " << head_ << ", " << body_ << ", wielding " << weapon_ << "\n";}private:std::string head_;std::string body_;std::string weapon_;
};// 抽象建造者
class CharacterBuilder {
public:virtual ~CharacterBuilder() = default;virtual void buildHead() = 0;virtual void buildBody() = 0;virtual void buildWeapon() = 0;virtual std::unique_ptr<GameCharacter> getResult() = 0;
};// 具體建造者:騎士
class KnightBuilder : public CharacterBuilder {
public:KnightBuilder() { character_ = std::make_unique<GameCharacter>(); }void buildHead() override { character_->setHead("Steel Helmet"); }void buildBody() override { character_->setBody("Plate Armor"); }void buildWeapon() override { character_->setWeapon("Longsword"); }std::unique_ptr<GameCharacter> getResult() override { return std::move(character_); }private:std::unique_ptr<GameCharacter> character_;
};// 具體建造者:法師
class MageBuilder : public CharacterBuilder {
public:MageBuilder() { character_ = std::make_unique<GameCharacter>(); }void buildHead() override { character_->setHead("Pointed Hat"); }void buildBody() override { character_->setBody("Robe"); }void buildWeapon() override { character_->setWeapon("Staff"); }std::unique_ptr<GameCharacter> getResult() override { return std::move(character_); }private:std::unique_ptr<GameCharacter> character_;
};// 指揮者(可選)
class CharacterDirector {
public:std::unique_ptr<GameCharacter> createCharacter(CharacterBuilder& builder) {builder.buildHead();builder.buildBody();builder.buildWeapon();return builder.getResult();}
};// 客戶端代碼
int main() {KnightBuilder knightBuilder;MageBuilder mageBuilder;CharacterDirector director;auto knight = director.createCharacter(knightBuilder);auto mage = director.createCharacter(mageBuilder);knight->describe(); // Character: Steel Helmet, Plate Armor, wielding Longswordmage->describe(); // Character: Pointed Hat, Robe, wielding Staffreturn 0;
}
代碼解析:
- 將角色構造分解為獨立步驟,新增角色類型只需添加新的
ConcreteBuilder
- 使用
std::unique_ptr
明確所有權轉移,防止資源泄漏
3.2 支持鏈式調用的增強實現
// 流暢接口(Fluent Interface)改進
class AdvancedCharacterBuilder {
public:AdvancedCharacterBuilder& withHead(const std::string& head) {head_ = head;return *this;}AdvancedCharacterBuilder& withBody(const std::string& body) {body_ = body;return *this;}AdvancedCharacterBuilder& withWeapon(const std::string& weapon) {weapon_ = weapon;return *this;}std::unique_ptr<GameCharacter> build() {auto character = std::make_unique<GameCharacter>();character->setHead(head_);character->setBody(body_);character->setWeapon(weapon_);return character;}private:std::string head_;std::string body_;std::string weapon_;
};// 客戶端使用
void createCustomCharacter() {auto builder = AdvancedCharacterBuilder();auto character = builder.withHead("Hood").withBody("Leather Armor").withWeapon("Dagger").build();character->describe();
}
代碼解析:
- 通過返回
this
指針實現鏈式調用,提升代碼可讀性 - 支持可選參數和任意順序設置屬性
4. 應用場景示例:HTTP請求構造
class HttpRequest {
public:void setMethod(const std::string& method) { method_ = method; }void setUrl(const std::string& url) { url_ = url; }void addHeader(const std::string& key, const std::string& value) {headers_[key] = value;}void setBody(const std::string& body) { body_ = body; }void send() const {std::cout << "Sending " << method_ << " " << url_ << " with body: " << body_ << "\n";}private:std::string method_;std::string url_;std::map<std::string, std::string> headers_;std::string body_;
};class HttpRequestBuilder {
public:HttpRequestBuilder() : request_(std::make_unique<HttpRequest>()) {}HttpRequestBuilder& method(const std::string& method) {request_->setMethod(method);return *this;}HttpRequestBuilder& url(const std::string& url) {request_->setUrl(url);return *this;}HttpRequestBuilder& header(const std::string& key, const std::string& value) {request_->addHeader(key, value);return *this;}HttpRequestBuilder& body(const std::string& body) {request_->setBody(body);return *this;}std::unique_ptr<HttpRequest> build() {return std::move(request_);}private:std::unique_ptr<HttpRequest> request_;
};// 使用示例
void sendPostRequest() {auto request = HttpRequestBuilder().method("POST").url("https://api.example.com/data").header("Content-Type", "application/json").body(R"({"key": "value"})").build();request->send();
}
5. 優缺點分析
優點 | 缺點 |
---|---|
分步驟構造復雜對象,代碼清晰 | 需定義多個Builder類,增加代碼量 |
支持不同配置和構造順序 | 對簡單對象可能過度設計 |
隔離復雜構造邏輯與業務代碼 | 需維護Builder與Product的同步 |
6. 調試與優化策略
- 參數驗證:在Builder方法中添加有效性檢查,防止非法狀態
- 對象復用:對頻繁創建的對象,實現reset()方法重用Builder實例
- 性能分析:使用std::move優化字符串等大型數據成員的傳遞效率