DownLoad
OGRE
分析之設(shè)計(jì)模式(四)
Mythma
Email: mythma@163.com
OGRE的設(shè)計(jì)結(jié)構(gòu)十分清晰,這得歸功于設(shè)計(jì)模式的成功運(yùn)用。
八、Iterator
說到Iterator,讓人首先想到的是STL中各種iterators。OGRE源碼中廣泛用到了STL,尤其是容器map。但OGRE大部分情況下并沒有直接使用與容器配套的迭代器,而是在iterator上包了一層。對(duì)序列式容器的iterator,OGRE包裝為VectorIterator<T>,其const形式為ConstVectorIterator;對(duì)關(guān)聯(lián)式容器(map),包裝為MapIterator<T>,其const形式為ConstMapIterator。所以從另一個(gè)角度看,使用的是Adapter模式。
OGRE的包裝本身沒有什么復(fù)雜,看一下map的iterator封裝就清楚了:
template <class T>
class MapIterator
{
private:
typename T::iterator mCurrent;
typename T::iterator mEnd;
/**//// Private constructor since only the parameterised constructor should be used
MapIterator() {};
public:
typedef typename T::mapped_type MappedType;
typedef typename T::key_type KeyType;
/**//** Constructor.
@remarks
Provide a start and end iterator to initialise.
*/
MapIterator(typename T::iterator start, typename T::iterator end)
: mCurrent(start), mEnd(end)
{
}
/**//** Returns true if there are more items in the collection. */
bool hasMoreElements(void) const
{
return mCurrent != mEnd;
}
/**//** Returns the next value element in the collection, and advances to the next. */
typename T::mapped_type getNext(void)
{
return (mCurrent++)->second;
}
/**//** Returns the next value element in the collection, without advancing to the next. */
typename T::mapped_type peekNextValue(void)
{
return mCurrent->second;
}
/**//** Returns the next key element in the collection, without advancing to the next. */
typename T::key_type peekNextKey(void)
{
return mCurrent->first;
}
/**//** Required to overcome intermittent bug */
MapIterator<T> & operator=( MapIterator<T> &rhs )
{
mCurrent = rhs.mCurrent;
mEnd = rhs.mEnd;
return *this;
}
/**//** Returns a pointer to the next value element in the collection, without
advancing to the next afterwards. */
typename T::pointer peekNextValuePtr(void)
{
return &(mCurrent->second);
}
/**//** Moves the iterator on one element. */
void moveNext(void)
{
mCurrent++;
}
};
九、Observer
Observer模式“定義對(duì)象間一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí),所有依賴他的對(duì)象都得到通知并自動(dòng)更新”。回想一下OGRE的消息機(jī)制,用的正是該模式。
為了得到OGRE的各種消息(更新、鼠標(biāo)、鍵盤),在初始化EventProcessor后需要向它添加各種Listeners:KeyListener、MouseListener、MouseMotionListener。而EventProcessor本身又是個(gè)FrameListener,在它startProcessingEvents的時(shí)候,又以FrameListener的身份注冊(cè)到Root中。可以看出,Root是消息的發(fā)布者,EventProcessor 是個(gè)代理,它把消息分發(fā)給各種訂閱者KeyListener、MouseListener或MouseMotionListener。
至于消息是如何分發(fā)的,可以參考Chain of Responsibility模式或消息機(jī)制分析。
十、Strategy
Strategy模式在于實(shí)現(xiàn)算法與使用它的客戶之間的分離,使得算法可以獨(dú)立的變化。
回想一下Bridge模式,可以發(fā)現(xiàn),兩者之間有些相似性:使得某一部分可以獨(dú)立的變化。只不過Bridge是將抽象部分與它的實(shí)現(xiàn)部分分離。從兩者所屬的類別來看,Bridge強(qiáng)調(diào)靜態(tài)結(jié)構(gòu),而Strategy強(qiáng)調(diào)更多的是行為——算法的獨(dú)立性。
同樣是Bridge模式中的例子,若把Mesh各版本文件讀取的實(shí)現(xiàn)看作是算法,把MeshSerializer看作是算法的客戶,那么該例也可以看作是Strategy模式。具體參考Bridge模式。
從上面可以看出,模式之間本沒有絕對(duì)的界限,從不同的角度看可以得到不同的結(jié)論;另一方面,模式的實(shí)現(xiàn)也是隨機(jī)應(yīng)變,要與具體的問題想結(jié)合。
十一、Template Method
Template Method比較簡(jiǎn)單的一個(gè)模式,屬于類行為模式。可以用“全局與細(xì)節(jié)”、“步驟與實(shí)現(xiàn)”來概括,具體就是基類定義全局和步驟,子類來實(shí)現(xiàn)每一步的細(xì)節(jié)。
OGRE給的Example框架使用了該模式,并具代表性。看一下ExampleApplication的setup()成員:
bool setup(void)
{
mRoot = new Root();
setupResources();
bool carryOn = configure();
if (!carryOn) return false;
chooseSceneManager();
createCamera();
createViewports();
// Set default mipmap level (NB some APIs ignore this)
TextureManager::getSingleton().setDefaultNumMipmaps(5);
// Create any resource listeners (for loading screens)
createResourceListener();
// Load resources
loadResources();
// Create the scene
createScene();
createFrameListener();
return true;
}
該成員函數(shù)調(diào)用的其他virtual成員函數(shù)都有默認(rèn)的實(shí)現(xiàn),若不滿足需求,子類可以自行實(shí)現(xiàn)。而setup()只是定義了一個(gè)設(shè)置順序。