oop - 接口(interface)因回调而臃肿

标签 oop design-patterns interface dependency-injection

想象一下以下类层次结构:

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/

相关文章:

C++:组合接口(interface)

python - 基于多态性的函数返回 None

java - 多态性,如何避免类型转换?

java - 什么时候应该使用对象而不是 json 对象?

c++ - 错误 : 'Friend Member Function Name' was not declared in this scope

java - java中从多个表检索数据时的最佳设计原则

java - 相同功能的两种变体的设计模式

C# 显式定义抛出哪些异常

c# - 迭代器与访问者设计模式以及如何

php - 使用抽象类和静态成员更好地管理功能