想象一下以下的类层次结构:
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界面将变得非常臃肿,包含游戏模式可能感兴趣的所有可能的东西,并且大多数调用将被删除! 如何防止这种情况?
编辑2:具体示例
答案 0 :(得分:1)
道歉,如果我错过了什么,但为什么不使用活动?基本上让IController
公开void Callback()
方法,然后Main可以订阅任何回调给自己的事件:
class Main
{
private event EventHandler SomeEvent;
public Main(IController controller)
{
// use weak events to avoid memory leaks or
// implement IDisposable here and unsubscribe explicitly
this.SomeEvent += controller.Callback;
}
public void ProcessStuff()
{
// invoke event here
SomeEvent();
}
}
这就是我要做的事情:将每个规则操作提取到单独的界面中,这样您就可以在具体的类中实现所需的内容,例如CaptureTheFlag
类现在仅执行PickupFlag
操作所以不会需要伤害/死亡方法,所以只需标记IPickupable
就可以了。然后检查具体实例是否支持具体操作并继续执行。
interface IPickupable
{
void NotifyPickup(object pickedUp);
}
interface IDeathable
{
void NotifyDeath();
}
interface IDamagable
{
void NotifyDamage();
}
class CaptureTheFlag : IPickupable
{
public void NotifyPickup(Pickup pickedUp)
{
if (pickedUp is Flag)
GameOver();
}
}
class DeathMatch : IPickupable, IDeathable
{
public void NotifyPickup(Pickup pickedUp)
{
points++;
}
public void NotifyDeath()
{
lives--;
}
}
class GameWorld
{
public void GameLoop()
{
foreach(object obj in worldObjects)
{
obj.Update();
IPickupable pickupable = gameMode as IPickupable;
IDeathable deathable = gameMode as IDeathable;
IDamagable damagable = gameMode as IDamagable;
if (pickupable != null)
{
pickupable.NotifyPickup();
}
if (deathable != null)
{
deathable.NotifyDeath();
}
if (damagable != null)
{
damagable.NotifyDamage();
}
}
}
}
答案 1 :(得分:1)
似乎你的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#的代理,......
答案 2 :(得分:0)
我的最终解决方案是xtofl发布的C#等价物。我创建了一个类,其中存储了一堆委托。这些委托开始时使用默认值(因此它们永远不会为null),并且不同的具体IRules类可以选择是否覆盖它们。这比抽象或存根方法效果更好,因为它不会使用不相关的方法阻塞接口。
class GameEvents
{
public Action<Player> PlayerKilled = p => {};
public Func<Entity, bool> EntityValid = e => true;
public Action ItemPickedUp = () => {};
public Action FlagPickedUp = () => {};
}
class IRules
{
GameEvents Events { get; }
}
class CaptureTheFlag : IRules
{
GameEvents events = new GameEvents();
public GameEvents Events
{
get { return events; }
}
public CaptureTheFlag()
{
events.FlagPickedUp = FlagPickedUp;
}
public void FlagPickedUp()
{
score++;
}
}
每个规则集都可以选择要收听的事件。游戏只需通过执行Rules.Events.ItemPickedUp();来调用。保证永远不会为空。
感谢xtofl的想法!