在XNA中将Game1静态化是一个坏主意吗?


10

将我的Game1课程设为静态真的不是一个好主意吗?就像目前在我的Game1课堂上一样,我有一个名为的类TileHandler,负责处理与我当前的那组瓷砖有关的AnimalHandler所有事情,并且处理所有我的动物(令人惊讶地)。

现在,如果我AnimalHandler要检查瓷砖是否TileHandler从那时起便是可步行的,这会引起问题,或者我必须将可步行瓷砖的列表传递到中AnimalHandler,而不希望这样做。

更简单的方法是将其设置为Game1静态,然后AnimalHandler直接运行Game1._tileHandler.WalkableTile(position)

现在,我看不到有任何立即出错的问题或会导致任何问题的任何事情,但是我只是刚刚开始使用静态类,所以,有什么知识渊博的人是否会看到任何大的原因来说明这是一个坏主意?

Answers:


9

现在,我看不到有任何立即出错的问题或会引起任何问题的任何事情,但是我只是刚刚开始使用静态类,所以,有什么知识渊博的人会看到任何大的原因,这是一个坏主意吗?

当您使用闪亮的新锤子时,每个问题都像钉子一样。

通常,如果正确使用静态类和/或方法(对于不具有或不依赖于每个实例状态的事物),则没有任何问题。但是,在您的情况下,您会滥用它们来隐藏每个实例的依赖关系,从而将其与删除依赖关系相混淆。看来您正在公开Game1该类的实现细节,这通常也是不好的。

这是您问题的症结所在:

...如果我进入AnimalHandler并要检查TileHandler从那时起是否可行走的瓷砖 会导致问题,或者我必须将可行走瓷砖的列表传递到中AnimalHandler,而我不希望这样做。

暂时忽略AnimalHandler需要这些磁贴本身可能是一个不好的设计的可能性(使用您选择的名称很难说出这些类的详细信息)...如果AnimalHandler需要一个可行走磁贴的列表,那么它需要一个步行砖。通常,使依赖项更明确比不依赖项更好,因为这会使代码更具自记录性。通过将列表直接传递给AnimalHandler,您可以明确指出它需要这样一个列表的事实。如果改为将所有内容设为静态和公共状态,以便仅访问代码中其他位置的静态列表,则您要做的就是隐藏依赖关系,而无需实际解决或删除它。

对于不需要扩展的小型游戏而言,这本身不是问题,但它可能会导致您走上不良习惯的道路,因此您可能要考虑不要这样做。至少要记住下一个项目。


阿们!您触及的重点是我在回答中并未真正提及。
Nate

+1隐藏依赖项并引入全局状态确实是这里的问题
ashes999

4

在静态上下文中调用TileHandler并不是最好的设计,其原因是它耦合了设计中可能会解耦的组件。

如果您将来选择拥有多个TileHandler,则必须做很多工作来适应这一变化。

如果选择删除TileHandler,则必须做很多工作来适应此更改。

假设您将来会构建一个不同的级别/区域,以与当前TileHandler不同的方式处理图块。然后,您要么需要一种方法来指定要使用的图块处理方法,要么需要调用其他处理程序。

如果将TileHandler作为参数传递给使用它的对象,那么您下次可以简单地传递一个不同的值,或者在以后使用它的对象上设置一个不同的瓦片处理程序。

就个人而言,我从静态上下文访问XNA游戏中的许多内容,并假设我永远不会拥有其中的多个内容。

如果您希望能够在下一个游戏中重用游戏引擎代码,则可能必须重写当前以静态方式编写的大部分内容。

简而言之:

赞成不使用静态上下文:

尽可能将对象作为参数传递,可以使游戏元素脱钩,并使您可以更轻松地针对当前或将来的项目修改/重用它们。它还使您可以更轻松地管理大量代码的复杂性(例如,在大型游戏中,游戏类中有数百个静态管理器)。

支持静态上下文:

从静态上下文声明和访问对象使编写不需要数百个静态管理器的小型游戏变得更加容易。通过不需要一个或多个静态访问的额外参数,简化了许多方法和构造函数。



2

诸如TileHandler和AnimalHandler之类的东西我会在游戏屏幕上放一个更高的级别。您的标题屏幕是否需要访问TileHandler并在首次加载游戏时进行初始化?可能不是。

查看XNA状态管理示例。它里面有很多代码,但是基本上,基本游戏只是初始化游戏状态(或屏幕)的堆栈。每个屏幕都与其他屏幕完全独立,并作为游戏本身的简化版本运行。您的PlayScreen可能具有静态成员,因此PlayScreen组件可以访问它们。

在基础游戏中,我确实使用了一些静态变量,但是它们是非常低级的东西,例如InputHelper,Log或Config阅读器。它们在所有游戏中都是非常标准的,因此可以快速轻松地移植基本引擎。屏幕是实际游戏逻辑发生的地方。这么长的答案很简短-不,从理论上讲,我不认为这是一个坏主意,只要小心使静态的内容即可。一旦您继续进行一些静态操作,如果您改变主意,将需要进行大量工作。


0

这里提出的观点都很好。根据我的经验(公认的是,商业应用比游戏更重要),静态类和成员有很好的用途,我已经使用了很多次。我发现,随着需求和复杂性的增长,我最终回收了这些静态类并将其转换为实例类并开始传递它们。

我想说明的一点是,如果使用静态类可以帮助您轻松开发这款游戏,请继续努力,但仍然可以做正确的事情:实现接口或基类,以便更轻松地将其提取出来并进行转换稍后将其添加到实例类。

一盎司的预防值得一磅的治疗,因此请确保您的静态课堂不会使您束手无策,这很难改变。使用实现了接口的静态类重构方法非常容易,因此它接受新的接口参数并使用该接口而不是静态类引用。


0

是的,这通常是一个坏主意。

将包含不断变化的数据(即只读常量和查找表以外的任何内容)的对象转换为静态类是好的设计的潜能。

  1. 它促进了偶然性依赖关系,从而破坏了模块化并妨碍了代码重用。假设您想为您的游戏编写一个编辑器-您突然之间会遇到很多类Game1,因为它们无法轻松进入共享库。

  2. 您的代码不可测试。单元测试通过模拟或模拟它们之间的依赖关系(应将它们保持在最小程度)来将各个类与其余类隔离开来。任何静态类都是责任,因为它可以随时访问,在多个测试中带有状态或在测试成功之前需要进行初始化。

  3. 它隐藏了依赖关系。就像服务提供者反模式(也由XNA,Game.Services所采用)一样,您的类可以选择在外部看不到的依赖项。

如果将静态类与货运调用结合在一起(thingsl ike- Game.Instance.ActorManager.Enemies.FindInRange(10)之所以称呼它是因为火车车厢式的链接符号),则这种方法特别有害。在这种情况下,组件突然不仅需要一个Game类,而且具有静态Instance属性的类需要返回一个带有一个ActorManager属性,该Enemies属性具有返回带有FindInRange()方法的对象的属性。

我编写可变静态类的唯一借口是仍在学习中,尚不能始终如一地应用良好的设计和训练有素的眼睛来发现错误的选择。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.