OGRE
分析之设计模式(四)
Mythma
Email: mythma@163.com
OGRE
的设计结构十分清晰,这得归功于设计模式的成功运用。
八、
Iterator
说到
Iterator
,让人首先想到的是
STL
中各种
iterators
。
OGRE
源码中广泛用到了
STL
,尤其是容器
map
。但
OGRE
大部分情况下并没有直接使用与容器配套的迭代器,而是在
iterator
上包了一层。对序列式容器的
iterator
,
OGRE
包装为
VectorIterator<T>
,其
const
形式为
ConstVectorIterator
;对关联式容器(
map
),包装为
MapIterator<T>
,其
const
形式为
ConstMapIterator
。所以从另一个角度看,使用的是
Adapter
模式。
OGRE
的包装本身没有什么复杂,看一下
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
模式“定义对象间一对多的依赖关系,当一个对象的状态发生变化时,所有依赖他的对象都得到通知并自动更新”。回想一下
OGRE
的消息机制,用的正是该模式。
为了得到
OGRE
的各种消息(更新、鼠标、键盘),在初始化
EventProcessor
后需要向它添加各种
Listeners
:
KeyListener
、
MouseListener
、
MouseMotionListener
。而
EventProcessor
本身又是个
FrameListener
,在它
startProcessingEvents
的时候,又以
FrameListener
的身份注册到
Root
中。可以看出,
Root
是消息的
发布者
,
EventProcessor
是个
代理
,它把消息分发给各种
订阅者
KeyListener
、
MouseListener
或
MouseMotionListener
。
至于消息是如何分发的,可以参考
Chain of Responsibility
模式或消息机制分析。
十、
Strategy
Strategy
模式在于实现算法与使用它的客户之间的分离,使得算法可以独立的变化。
回想一下
Bridge
模式,可以发现,两者之间有些相似性:使得某一部分可以独立的变化。只不过
Bridge
是将抽象部分与它的实现部分分离。从两者所属的类别来看,
Bridge
强调静态结构,而
Strategy
强调更多的是行为——算法的独立性。
同样是
Bridge
模式中的例子,若把
Mesh
各版本文件读取的实现看作是算法,把
MeshSerializer
看作是算法的客户,那么该例也可以看作是
Strategy
模式。具体参考
Bridge
模式。
从上面可以看出,模式之间本没有绝对的界限,从不同的角度看可以得到不同的结论;另一方面,模式的实现也是随机应变,要与具体的问题想结合。
十一、
Template Method
Template Method
比较简单的一个模式,属于类行为模式。可以用“全局与细节”、“步骤与实现”来概括,具体就是基类定义全局和步骤,子类来实现每一步的细节。
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
;
}
该成员函数调用的其他
virtual
成员函数都有默认的实现,若不满足需求,子类可以自行实现。而
setup
()只是定义了一个设置顺序。