Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 接口因回调而膨胀_Oop_Design Patterns_Interface_Dependency Injection - Fatal编程技术网

Oop 接口因回调而膨胀

Oop 接口因回调而膨胀,oop,design-patterns,interface,dependency-injection,Oop,Design Patterns,Interface,Dependency Injection,设想以下类层次结构: 接口病毒 { 无效拾取(对象拾取); 死亡无效(); 无效损害(); } 类CAPTURATEFLAG:IRules { 公共接收(接收接收接收) { 如果(pickedUp是标志) GameOver(); } 公众死亡 { } 公共财产损失() { } } 类死亡竞赛:病毒 { 公共接收(接收接收接收) { 积分++; } 公众死亡 { 生命--; } 公共财产损失() { } } 职业游戏世界 { 病毒游戏模式; 公用主(IRules游戏模式) { this.gameM

设想以下类层次结构:

接口病毒
{
无效拾取(对象拾取);
死亡无效();
无效损害();
}
类CAPTURATEFLAG:IRules
{
公共接收(接收接收接收)
{
如果(pickedUp是标志)
GameOver();
}
公众死亡
{
}
公共财产损失()
{
}
}
类死亡竞赛:病毒
{
公共接收(接收接收接收)
{
积分++;
}
公众死亡
{
生命--;
}
公共财产损失()
{
}
}
职业游戏世界
{
病毒游戏模式;
公用主(IRules游戏模式)
{
this.gameMode=gameMode;
}
对象[]世界对象;
public void GameLoop()
{
foreach(worldObjects中的对象对象对象)
{
//这通电话可能会有很多副作用,比如接电话
//或者一个球员死了
//或受到损害
//不同的游戏模式对不同的事件/统计信息感兴趣。
obj.Update();
//事情发生了。。。
gameMode.NotifyDamage();
//事情发生了。。。
gameMode.NotifyDeath();
}
}
}
这里有一个包含Notify*函数的接口。这些是回调。不同的游戏模式对游戏中的不同事件感兴趣。实际上不可能访问创建这些事件的具体对象,因为它们埋在worldObjects数组中。想象一下,我们正在为游戏添加新的游戏模式。IRules界面将变得非常臃肿,包含游戏模式可能感兴趣的所有可能的东西,并且大多数调用都会被打断我如何防止这种情况发生?


编辑2:具体示例

如果我错过了什么,我会道歉,但为什么不使用事件?基本上,让IControllerexpose
void Callback()
方法,然后Main将能够订阅任何回调到自己的事件:

主类
{
私有事件处理程序;
公用干管(IController-controller)
{
//使用弱事件来避免内存泄漏或
//在此处实现IDisposable并显式取消订阅
this.SomeEvent+=controller.Callback;
}
公共文件
{
//在这里调用事件
SomeEvent();
}        
}

编辑: 这就是我要做的:将每个规则操作提取到单独的接口中,这样您就可以在具体的类中实现所需的内容,例如
capturateflag
class现在只执行
pickupfag
操作,所以不需要损坏/死亡方法,所以只需通过
IPickupable
标记即可。然后只需检查具体实例是否支持具体操作,然后继续执行

接口IPickupable
{
无效拾取(对象拾取);
}
接口可寻址
{
死亡无效();
}
可识别接口
{
无效损害();
}    
类CAPTURATEFLAG:IPickupable
{
公共接收(接收接收接收)
{
如果(pickedUp是标志)
GameOver();
}
}
类死亡匹配:IPickupable,IDeathable
{
公共接收(接收接收接收)
{
积分++;
}
公众死亡
{
生命--;
}
}
职业游戏世界
{
public void GameLoop()
{       
foreach(worldObjects中的对象对象对象)
{
obj.Update();
IPickupable pickupable=游戏模式为IPickupable;
IDeathable deathable=游戏模式为IDeathable;
IDamagable damagable=游戏模式为IDamagable;
if(可拾取!=null)
{
pickupable.NotifyPickup();
}
if(可终止!=null)
{
死亡;死亡;
}
如果(可损坏!=null)
{
可损坏的;可损坏的;
}                      
}
}
}

看起来您的
过程逻辑发出了很多事件。如果你给这些活动起个名字,你可以订阅你的观察员

然后甚至可以创建一个“过滤”观察者,它可以将事件转发给任何其他观察者(装饰器模式):

注意:代码未经测试-抓住想法


如果您真的想将发送方与接收器分离,那么可以在两者之间放置一个事件系统。这里给出的示例非常专用且轻量级,但一定要看看各种现有的实现:在中和中实现的信号和插槽,来自C#的代理,…

我的最终解决方案是C#等价于xtofl发布的内容。我创建了一个类,其中存储了一堆委托。这些委托从默认值开始(因此它们永远不会为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++;
    }
}
类游戏事件
{
公共行动玩家killed=p=>{};
public Func EntityValid=e=>true;
公共操作项pickedup=()=>{};
公共操作FlagPickedUp=()=>{};
}
类病毒
{
GameEvents事件{get;}
}
类CAPTURATEFLAG:IRules
{
GameEvents=新GameEvents();
公开游戏活动
{
获取{返回事件;}
}
公共CAPTURATEFLAG()
{
events.FlagPickedUp=FlagPickedUp;
}
公共无效FlagPickedUp()
{
分数++;
}
}
每个规则集都可以选择要侦听的事件。游戏只需执行Rules.Events.ItemPickedUp();,即可调用;。它保证永远不会为空


感谢xtofl的创意

这与方法调用有何不同?所有的事件定义必须仍然在接口中
Main main;

EventEventDispatcher f1;

f1.listeners[Event::A].push_back(listener1);

main.listener=f1;
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++;
    }
}