2013-01-03 14 views
0

我有一個使用內部對象Builder實例化複雜對象的構造函數。數據結構中的五個成員是指針類型。但是,使用這種模式時,我遇到了對象被破壞時的問題。下面是我的構造的樣子,與成員初始化列表:在使用Builder模式的構造函數中將指針類型的成員數據初始化爲NULL

Player::Player(const Builder& builder) 
    :m_name(builder._name) 
    ,m_description(builder._description) 
    ,m_primaryAttributes(builder._primaryAttributes) 
    ,m_abilityAttributes(builder._abilityAttributes) 
    ,m_armor(builder._armor) 
    ,m_weapon(builder._weapon) 
    ,m_inventory(new ComponentMap()) 
{} 

客戶端代碼工作得很好,符合市場預期:

Player* player = Player::Builder() 
    .name("Dylan") 
    .description("Super bad-ass hero of the game") 
    .primaryAttributes(createPrimaryAttributes()) 
    .abilityAttributes(createAbilityAttributes()) 
    .weapon(createWeapon()) 
    .armor(createArmor()) 
    .build(); 

但是,如果我忽略的一個參數的消息鏈,然後摧毀我Player對象,壞的事情發生:

Player* player = Player::Builder() 
    .name("Dylan") 
    .description("Super bad-ass hero of the game") 
    .primaryAttributes(createPrimaryAttributes()) 
    .abilityAttributes(createAbilityAttributes()) 
    .armor(createArmor()) 
    .build(); 

// ... 

delete player; 

// ... 

// cleanMemory() gets called in Player::~Player() 
void Player::cleanMemory() 
{ 
    if(m_primaryAttributes != NULL) 
     delete m_primaryAttributes; 
    if(m_abilityAttributes != NULL) 
     delete m_abilityAttributes; 
    if(m_inventory != NULL) 
     delete m_inventory; 
    if(m_weapon != NULL)   // oops, bad stuff happens here 
     delete m_weapon; 
    if(m_armor != NULL) 
     delete m_armor; 
} 

顯然,出現這種情況是因爲指針武器沒有得到初始化要麼NULLWeapon對象的實例。在鏈中省略了一個Builder方法的情況下,該構造函數也不會允許缺省爲NULL(至少從我所能看到的情況來看)。目前,客戶必須給Weapon一個指向NULL的指針或一個對象的實例。

是否有任何可能的方式來解決這個問題而不完全修改這個Builder構造函數?或者,是否應該使用另一種模式重構,如Factory,然後回到帶位置參數列表的常規構造函數?

+2

請向我們展示'Player :: Builder'函數? – billz

+2

使用smartpointers? –

+1

我的第一個想法是智能指針。這將完全消除cleanMemory()。 – drescherjm

回答

1

你提到我的示例代碼不是很好的代碼庫,我只想建議如下build pattern

class Builder 
{ 
    Weapon* BuildWeapon() { return new Weapon(); } 
    Armor* BuildArmor(); { return new Armor(); }  
}; 

class Player 
{ 
public: 
    Player(const Builder& builder) 
    : weapon_ptr(builder.BuildWeapon()), 
    armer_ptr(builder.BuildArmor()) 

private: 
    std::shared_ptr<Weapon> weapon_ptr; 
    std::shared_ptr<Armor> armor_ptr; 
}; 

用法:

Builder builder; 
std::shared_ptr<Player> player(new Player(builder)); 

或者你可以只

class Player2 
{ 
public: 
    Player() {} 
    void SetWeapon(Weapon* p) { weapon_ptr.reset(p); } 
    void SetArmor(Armor* p) { armor_ptr.reset(p); } 

private: 
    std::shared_ptr<Weapon> weapon_ptr; 
    std::shared_ptr<Armer> armer_ptr; 
}; 

用法:

Builder builder; 
    std::shared_ptr<Player> player; 
    player->SetWeapon(builder.BuildWeaper()); 
    player->SetArmor(builder.BuildArmor()); 

由於weapon_ptr,armer_ptr是智能指針,因此不需要再調用delete作爲動態分配的內存,因此可以刪除cleanMemory()函數。

這只是一個簡單的示例,您可以擴展播放器的界面,以便在創建播放器對象後提供構建不同元素的功能。

+0

謝謝。在我之前的實現中,我使用了上面建議的''Builder'在自己的類中,而不是嵌套在'Player'類中。然而,我現在的解決方案使用了一個'Builder'接口,每個複雜的對象都使用它自己的嵌套Builder,它實現了'Builder'接口。通過這種方式,我可以在需要它的每個類中封裝'Builder'功能,而不必在每次創建複雜對象時都實例化一個'Builder'對象。不過,我會用智能指針來運行你的想法。 – dtg

+0

將Builder對象傳遞給Player construtor或不是最小的問題,它是一個小的設計風格變化。 – billz

相關問題