想象一下以下类层次结构:
interface IRules
{
void NotifyPickup(object pickedUp);
void NotifyDeath();
void NotifyDamage();
}
class CaptureTheFlag : IRules
{
public void NotifyPickup(Pickup pickedUp)
{
if(pickedUp is Flag)
GameOver();
}
public void NotifyDeath()
{
}
public void NotifyDamage()
{
}
}
class DeathMatch : IRules
{
public void NotifyPickup(Pickup pickedUp)
{
points++;
}
public void NotifyDeath()
{
lives--;
}
public void NotifyDamage()
{
}
}
class GameWorld
{
IRules gameMode;
public Main(IRules gameMode)
{
this.gameMode = gameMode;
}
object[] worldObjects;
public void GameLoop()
{
foreach(object obj in worldObjects)
{
// This call may have a bunch of sideeffects, like getting a pickup
// Or a player dying
// Or damage being taken
// Different game modes are interested in different events / statistics.
obj.Update();
// Stuff happens...
gameMode.NotifyDamage();
// Stuff happens...
gameMode.NotifyDeath();
}
}
}
所以这里我有一个包含 Notify* 函数的界面。这些是回调。不同的游戏模式对游戏的不同事件感兴趣。实际上不可能访问创建这些事件的具体对象,因为它们被隐藏在 worldObjects 数组中。想象一下我们正在向游戏添加新的游戏模式。 IRules 接口(interface)将变得非常臃肿,包含游戏模式可能感兴趣的所有可能的内容,并且大多数调用将被 stub ! 如何防止这种情况发生?
编辑2:具体示例
最佳答案
看起来你的Process
逻辑发出了很多事件。如果您给这些事件一个名称,您就可以为您的观察者订阅它们。
然后甚至可以创建一个“过滤”观察者,它可以将事件转发给任何其他观察者(装饰器模式):
struct Event {
enum e { A, B, /*...*/ };
e name;
};
class IEventListener {
public:
virtual void event( Event e ) = 0;
};
// an event dispatcher implementation:
using namespace std;
class EventDispatcher {
public:
typedef std::shared_ptr<IEventListener> IEventListenerPtr;
map<Event::e,vector<IEventListenerPtr>> listeners;
void event(Event e){
const vector<IEventListenerPtr> e_listeners=listeners[e.name].second;
//foreach(begin(e_listeners)
// ,end(e_listeners)
// ,bind(IEventListener::event,_1,e));
for(vector<IEventListenerPtr>::const_iterator it=e_listeners.begin()
; it!=e_listeners.end()
; ++it)
{
(*it)->event(e);
}
}
};
您的程序可能如下所示:
Main main;
EventEventDispatcher f1;
f1.listeners[Event::A].push_back(listener1);
main.listener=f1;
注意:代码未经测试 - 捕获想法。
如果您确实想将发送方与接收方分离,您可以在两者之间放置一个事件系统。这里给出的示例非常专用且轻量级,但请务必查看各种现有的实现: Qt 中实现的信号和槽。并在 Boost ,来自 C# 的代表,...
关于oop - 接口(interface)因回调而臃肿,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11267339/