我正在写一个有很多组件的游戏。其中许多是相互依赖的。在创建它们时,我经常会遇到catch-22情况,比如“WorldState
的构造函数需要一个PathPlanner
,但是PathPlanner
的构造函数需要WorldState
”。具有相互依赖性的组件的初始化 - 可能的反模式?
最初,这个问题不大,因为引用所需的所有东西都在GameEngine
左右,并且GameEngine
被传递到了所有东西。但我不喜欢这种感觉,因为它感觉我们对不同组件的访问权限过大,使得实施边界变得更加困难。
这里是有问题的代码:
/// <summary>
/// Constructor to create a new instance of our game.
/// </summary>
public GameEngine()
{
graphics = new GraphicsDeviceManager(this);
Components.Add(new GamerServicesComponent(this));
//Sets dimensions of the game window
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
graphics.ApplyChanges();
IsMouseVisible = true;
screenManager = new ScreenManager(this);
//Adds ScreenManager as a component, making all of its calls done automatically
Components.Add(screenManager);
// Tell the program to load all files relative to the "Content" directory.
Assets = new CachedContentLoader(this, "Content");
inputReader = new UserInputReader(Constants.DEFAULT_KEY_MAPPING);
collisionRecorder = new CollisionRecorder();
WorldState = new WorldState(new ReadWriteXML(), Constants.CONFIG_URI, this, contactReporter);
worldQueryUtils = new WorldQueryUtils(worldQuery, WorldState.PhysicsWorld);
ContactReporter contactReporter = new ContactReporter(collisionRecorder, worldQuery, worldQueryUtils);
gameObjectManager = new GameObjectManager(WorldState, assets, inputReader, pathPlanner);
worldQuery = new DefaultWorldQueryEngine(collisionRecorder, gameObjectManager.Controllers);
gameObjectManager.WorldQueryEngine = worldQuery;
pathPlanner = new PathPlanner(this, worldQueryUtils, WorldQuery);
gameObjectManager.PathPlanner = pathPlanner;
combatEngine = new CombatEngine(worldQuery, new Random());
}
这里是上面说的有问题的摘录:
gameObjectManager = new GameObjectManager(WorldState, assets, inputReader, pathPlanner);
worldQuery = new DefaultWorldQueryEngine(collisionRecorder, gameObjectManager.Controllers);
gameObjectManager.WorldQueryEngine = worldQuery;
我希望没有人会忘记设置gameObjectManager.WorldQueryEngine
是,否则会失败。问题如下:gameObjectManager
需要WorldQuery
,而WorldQuery
需要gameObjectManager
的属性。
而且,除了这个问题,这是一个可维护性的混乱,因为如果构造函数没有以特定顺序调用,程序将崩溃。
我该怎么办?我有没有发现反模式?
好吧,这对我发布的摘录很好,因为'GameObjectManager'本身不是依赖项,但它的一个属性是。但是当两个对象需要彼此的实例并且不能在没有它的情况下实例化时呢? (所以,如果所有'GameObjectManager'都是必需的,而不仅仅是'GameObjectManager.Controllers') – 2010-04-02 16:51:46
@Rosarch:你指的是一个循环依赖。通常,这被认为是设计错误,但递归数据结构和辅助对象的明显例外仅依赖于负责创建和管理它们的相同对象(如资源池)。在其他情况下,当你有一个循环依赖时,通常在一个或两个依赖关系中有一部分功能可以被重构到它自己的类中,这样就不必让两个类相互依赖,而是依赖于第三(新)班。 – Aaronaught 2010-04-02 17:07:07
我还想指出的是,在我的游戏术语中,“游戏对象”是指世界上的一个实体,如树或玩家。这并不意味着OOP意义上的对象。 – 2010-04-05 21:12:08