我的代码中存在循环依赖,我不知道如何解决它。
我正在开发一款游戏。 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);
(上面的示例将参数简化了一点。)
如果没有act
和think
,controller
无法执行任何操作,因此我不希望在没有它们的情况下对其进行初始化。反之亦然。我该怎么办?
ControllerNPC
使用think
和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);
}
// ...
}
答案 0 :(得分:4)
使用接口将控制器的模型与具体的controllerService分开。
这是关于域驱动设计中的项目引用,我之前写了一篇关于这个问题的小博客:
http://www.mellekoning.nl/index.php/2010/03/11/project-references-in-ddd/
答案 1 :(得分:0)
使用两阶段构造,其中对象构造为对其相关对象的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.
答案 2 :(得分:0)
是否可以将事件用于对象之间的某些通信?
答案 3 :(得分:0)
根据我的理解,第一个和主要的是:控制器不应该知道思考,感知,行动......
我看到你有类似控制器的“更新”方法,而且(我猜)控制器需要做一些事情,这取决于当前的'思考','感知','表演'。
对于这种情况,我会在模型级别添加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.
}
}
希望这有帮助。
P.S。在某种程度上,建议的“架构”似乎与用户界面应用程序中使用的MVP模式类似。