【问题标题】:God object or where to keep subsystems references上帝对象或保存子系统引用的位置
【发布时间】:2013-06-08 22:36:42
【问题描述】:

我的游戏有很多子系统。他们可以互相使用。早些时候,我正在初始化子系统引用并将其存储到静态 Game 对象中,而不是制作单例。现在我看到 Game 对其他类的引用太多,看起来很混乱:

public static PlayerSettings PlayerSettings { get { return _playerSettings; } }

public static CommunityClient Community { get; private set; }
public static DatabaseConnectionWrapper Database { get; set; }
public static LoginConnectionWrapper LoginProtocolConnection { get; set; }
public static WorldEmulatorConnection WorldEmulatorConnection { get; set; }
public static WorldPlayerConnection WorldPlayerConnection { get; set; }
public static WorldConnection WorldConnection { get { return IsEmulatorMode ? (WorldConnection)WorldEmulatorConnection : WorldPlayerConnection; } }

public static MusicManager MusicManager { get; private set; }
public static SkyboxManager SkyboxManager { get; private set; }

public static VKInfo VK { get; private set; }

我该怎么办?我不需要这些子系统的抽象。而且我认为单例并不适合这种情况 - 架构看起来被分割成碎片。我想从一个地方以正确的顺序初始化我的所有子系统。但是引用的类太多了……


添加
查看 DI - 我可以将依赖项发送到类构造函数并初始化静态工厂中的每个类。这就是我要找的。
但我刚刚意识到我的问题是,当我尝试使用 Unity3D 对象组件架构时,我无法将依赖项发送到构造函数,因为类初始化是从 UnityEngine 调用的。
所以在这种情况下,我需要 Singleton 或 Blob 来保留引用。如果我抛弃 Unity 架构,那么我将从构造函数获取所有依赖项,并且不需要单例或 blob。
我需要重新设计我的架构,UnityEngine 不会创建需要获取子系统引用的对象,而是从我的代码中创建这些类并让他们创建和管理他们的 UnityEngine“游戏对象”。

【问题讨论】:

  • 这也称为The Blob - 请参阅sourcemaking.com/antipatterns/the-blob。一个可能的选择是考虑你的班级在做什么;你可以有一个带有播放器、社区和登录设置的PlayerManager,一个带有所有世界类的WorldManager,以及一个带有相关类的EnvironmentManager。这些中的每一个都将您的问题分解为更易于管理的块。然后您也可以开始执行 SRP - en.wikipedia.org/wiki/Single_responsibility_principle
  • 我很想知道您为什么认为它引用了“太多的类”?从您的描述来看,这似乎是对您所描述的问题的合理解决方案 - 以正确的顺序初始化。下一个最好的方法是将每个子系统解耦到每个子系统可以独立编译和运行的程度,这也有利于使测试更容易:)
  • 依赖注入是通常的解决方案,但你已经拒绝了。问题不在于上帝,而在于您在代码中调用他的名字的频率。当你有这么多全局变量时,可能会很多。所以也许你不应该拒绝 DI。
  • @HansPassant,你把我搞砸了!我告诉你。现在,就您而言,Vlad,为什么不听从 Hans 所说的,让您的生活更轻松一些,然后使用像 Unity 这样的 DI 容器来初始化 恢复这些对象。看,使用容器,您不需要逐字编写代码来传递所有依赖项,容器会为您完成这些,它甚至可以自己处理自定义初始化和单例。
  • 哪里提到了弗拉德对 DI 的厌恶?他在宽限期内把它删掉了吗?

标签: c# design-patterns singleton god-object


【解决方案1】:

查看 DI - 我可以将依赖项发送到类构造函数并初始化静态工厂中的每个类。这就是我要找的。 但是我刚刚意识到我的问题是,当我尝试使用 Unity3D 对象组件架构时,我无法将依赖关系发送到构造函数,因为类初始化是从 UnityEngine 调用的。 所以在这种情况下,我需要 Singleton 或 Blob 来保留引用。如果我抛出 Unity 架构,那么我将从构造函数获取所有依赖项,并且不需要单例或 blob。 我需要重新设计我的架构,UnityEngine 不会创建需要获取子系统引用的对象,而是从我的代码中创建这些类并让他们创建和管理他们的 UnityEngine“游戏对象”。

【讨论】:

    【解决方案2】:

    我认为你把事情复杂化了,弗拉德。

    由于您的管理器、控制器和诸如此类的东西不需要从 MonoBehaviour 继承,这变成了将子系统组织在一个对象下的简单案例,该对象只是作为访问它们的便利点。

    如果您有实际需要具有 MonoBehaviour 的管理器对象,则可以通过简单的 OnLevelLoaded 事件从加载的场景中获取这些引用,或者您自己将从实际触发场景加载的任何对象中引发的事件。 触发事件后,使用 Unity api 提供的 FindObjectOfType 方法从场景中查找您的游戏对象。

    因此,在一天结束时,一个单例类(即您的上帝对象)将跟踪您的所有子系统,任何场景绑定都将通过使用简单的 api 调用从加载的场景中收集。

    仅此而已。这听起来可能很复杂,但事实并非如此。

    【讨论】:

      猜你喜欢
      • 2015-11-07
      • 2014-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 2016-02-02
      • 1970-01-01
      相关资源
      最近更新 更多