2010-02-19 78 views
2

在我的遊戲引擎中,我有一個代表遊戲世界的狀態類。該狀態包含許多Body對象,每個對象都定義一個剛體。每個狀態都有一個容器來跟蹤它擁有的Body對象,並且每個Body都有一個指向其父狀態的指針。容器關係和封裝

綱要州級:

class State { 
private: 
    std::set<Body*> _bodies; 

public: 
    //It could be done here 
    void addBody(Body* body) { 
    //Remove from old State 
    if (body->_state) 
     body->_state->_bodies.erase(this); 

    //Set Body's back-reference 
    body->_state = this; 

    //Add to this State 
    _bodies.insert(body); 
    } 
}; 

體類概況:

class Body { 
private: 
    State* _state; 

public: 
    //It could also be done here 
    void setState(State* state) { 
    //Remove from old State 
    if (_state) 
     _state->_bodies.erase(this); 

    //Set back-reference 
    _state = state; 

    //Add to the new State 
    if (_state) 
     _state->bodies.insert(this); 
    } 
}; 

的問題,如果有一個,就是添加/刪除一個機構/從一個國家需要改變每個人的私人成員。

有一次,我考慮有一個狀態 - 介體靜態類,它有朋友訪問這兩個類。這聽起來不錯,因爲狀態與身體的關係將由這個名字明確地管理,但是對於管理一個簡單的關係來說,這是很多的聲明開銷。

有沒有「更好」的方法來做到這一點?我想看看那裏有什麼想法。

回答

1

嗯,你可以做這件事是有兩個類的友元函數:

void associate(State& s, Body& b) 
{ 
    s.addBody(&b); 
    b.setState(&s); 
} 
+0

這是真的,沒有任何理由,每個關係管理功能必須在一個單獨的類。 – mvanbem 2010-02-19 17:37:52

0

在第一遍,我將兩種方法結合起來:

void State::addBody(Body* body) { 
    //Add to this State 
    bodies_.insert(body); 

    //Remove from old State 
    body->setState(this); 
} 

void State::removeBody(Body* body) { 
    bodies_.erase(body); 
} 


void Body::setState(State* state) { 
    if(state_) { 
     state_->removeBody(this); 
    } 
    state_ = state; 
} 

這將國家和機構的內部分離開來,所以你可以例如對狀態的身體列表使用一些完全不同的機制,並且身體不需要知道它。你會想要小心異常安全;這個例子有意將容器插入開始,所以如果拋出,對象的狀態不會改變,但我不確定這裏沒有其他東西可以拋出。

請注意,我將下劃線移到了成員變量的末尾;我知道主要的下劃線是一個常見的約定,但它們實際上是由C++標準保留給編譯器的。

+0

那麼,只要沒有大寫字母,實際上前面的下劃線都可以。不過,由於我自己的審美原因,我更喜歡尾隨的下劃線。 – rlbond 2010-02-19 23:47:14

0

私人的目的是要有一個類負責維護身體 - 國家聯繫。實際效果是,當聯繫出現問題或需要以某種方式加強時,您只有一個班級進行檢查或修改。你可以用朋友來分擔責任,但是你可能會爲自己長期頭痛。我會保留一個或兩個班的「啞巴」。

// example 1: dumb state 
void State::addBody(Body* body) { _bodies.insert(body); } 
void State::removeBody(Body* body) { _bodies.erase(body); } 
void Body::setState(State* state) 
{ 
    if(_state) _state->removeBody(this); 
    if(state) state->addBody(this); 
    _state = state; 
} 

// example 2: dumb body 
void Body::setState(State* state) { _state = state; } 
State* Body::getState() const { return _state; } 
void State::addBody(Body* body) 
{ 
    if(body && body->getState() != this) 
    { 
     body->getState()->_bodies.erase(body); 
     _bodies.insert(body); 
     body->setState(this); 
    } 
} 

// example 3: both are dumb 
void State::addBody(Body* body) { _bodies.insert(body); } 
void State::removeBody(Body* body) { _bodies.erase(body); } 
void Body::setState(State* state) { _state = state; } 
State* Body::getState() const { return _state; } 
void BodyStateMachine::setBodyState(Body* body, State* state) 
{ 
    if(body && body->getState() != state) 
    { 
     body->getState()->removeBody(body); 
     state->addBody(body); 
     body->setState(state); 
    } 
} 

您選擇的方法應該取決於哪個類將更公開使用(您更希望其他代碼管理「智能」類)。你可以通過創建一個不暴露getter/setter函數的接口來進一步保護啞類。