繁体   English   中英

C#:如何解决这个循环依赖?

[英]C#: How to resolve this circular dependency?

我的代码中有循环依赖,我不知道如何解决它。

我正在开发一款游戏。 NPC有三个组成部分,负责思考,感知和行动。 这些组件需要访问NPC控制器才能访问其模型,但控制器需要这些组件才能执行任何操作。 因此,两者都在其构造函数中将彼此视为参数。

ISenseNPC sense = new DefaultSenseNPC(controller, worldQueryEngine);
IThinkNPC think = new DefaultThinkNPC(sense);
IActNPC act = new DefaultActNPC(combatEngine, sense, controller);
controller = new ControllerNPC(act, think);

(上面的例子简化了一些参数。)

没有actthinkcontroller不能做任何事情,所以我不想让它在没有它们的情况下进行初始化。 反之亦然。 我该怎么办?

ControllerNPC使用think and act来更新它在世界上的状态:

public class ControllerNPC {
   // ...
           public override void Update(long tick)
        {
            // ...
            act.UpdateFromBehavior(CurrentBehavior, tick);

            CurrentBehavior = think.TransitionState(CurrentBehavior, tick);
        }
   // ...

}

DefaultSenseNPC使用controller来确定它是否与任何东西发生碰撞:

 public class DefaultSenseNPC {
       // ...
            public bool IsCollidingWithTarget()
            {
                return worldQuery.IsColliding(controller, model.Target);
            }
       // ...
    }

使用接口将控制器的模型与具体的controllerService分开。

这是关于域驱动设计中的项目引用,我之前写了一篇关于这个问题的小博客:

http://www.mellekoning.nl/index.php/2010/03/11/project-references-in-ddd/

使用两阶段构造,其中对象构造为对其相关对象的null引用,然后调用set方法来设置引用:

ISenseNPC sense = new DefaultSenseNPC(worldQueryEngine);
IThinkNPC think = new DefaultThinkNPC();
IActNPC act = new DefaultActNPC(combatEngine);
controller = new ControllerNPC();

sense.setController(controller);
think.setSense(sense);
act.setSense(sense);
act.setController(controller);
controller.setAct(act);
controller.setThink(think);

// And now the objects are ready to use.

是否可以将事件用于对象之间的某些通信?

根据我的理解,第一个和主要的是:控制器不应该知道思考,感知,行动......

我看到你有类似控制器的'更新'方法和(我猜)控制器需要根据当前的'思考','感知','表演'做一些事情。

对于这种情况,我会在模型级别添加3个组件:'ThinkModel','ActModel','SenseModel'。 它们应代表相应过程的状态,对其他世界一无所知。

您的控制器应通过“DoAction”,“ThinkingAbout”,“FeelingSomething”等方法从组件(思考,表演,感知)接收此信息并将其存储在内部。

同时它应该有一系列事件,如'ActionOccured','ThinkingOccured','SenseingOcured'(最后可以表达为'FeeledSomething')。 这些事件应该是:

  • 在任何州改变的情况下被解雇;
  • 提供相应的对象模型;
  • 应该由组件听取。

因此,您将让控制器仅了解模型,并且每个组件都可以参考所有模型和控制器。 组件需要彼此不了解。 控制器需要对组件一无所知。 您将能够以这样的方式创建对象:

IThinkModel modelThinkg = new ThinkModel();
IActModel modelAct = new ActModel();
ISenseModel modelSense = new SenseModel();

IController controller = new Controller(modelThinkg, modelAct, modelSense);

ISenseNPC sense = new DefaultSenseNPC(controller);
IThinkNPC think = new DefaultThinkNPC(sense);
IActNPC act = new DefaultActNPC(combatEngine, sense, controller);

每个组件的构造函数可以如下所示:

class DefaultSenseNPC
{
    DefaultSenseNPC(IController controller)
    {
        _controller = controller;
        _contoller.ThinkingAbout += ContollerReceivedNewThinking;
    }

    private ContollerReceivedNewThinking(IModelThinking modelNewThink)
    {
        _modelNewThink = modelNewThink;// store it for further calculations.
    }
}

希望这可以帮助。

PS在某种程度上,建议的“架构”似乎与用户界面应用程序中使用的MVP模式类似。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM