12

我正在将游戏从单人游戏更新为多人游戏。在这种情况下,游戏最初是在大多数类都是单实例的情况下编写的。例如,有一个 Player 对象、一个 GameState 对象等。也就是说,这些对象中的每一个都与应用程序一样长。

既然可以同时玩多个玩家,我显然需要支持创建多个 Player 对象、GameState 对象等。在此过程中,我开始意识到大多数对象具有以下三种生命周期之一:

  1. 应用程序的生命周期,例如处理导航的指挥
  2. 玩家的生命周期,例如当前玩家的 SettingsViewModel
  3. 游戏的生命周期,例如当前游戏的 GameState

我很好奇其他人如何使用 IoC 容器来处理这些不同对象的创建。我想避免为每个具有玩家或游戏生命周期的类创建工厂类。

4

4 回答 4

0

许多 IoC 容器都有自定义的生命周期范围,您可以根据自己的意愿进行管理。例如,在 Ninject 中,您可以定义自定义生命周期范围,如下所示:

kernel.Bind<IService>().To<Service>().InScope((c, o) => yourCustomeScope);

只要 yourCustomeScope 变量没有改变,内核每次收到 IService 请求时都会返回一个 Service 对象实例。一旦 yourCustomeScope 变量发生变化,就会在下一次请求 IService 时创建一个新的 Service 实例。yourCustomeScope 可以是当前玩家实例、游戏对象或任何您想根据其引用更改更改 Service 对象生命周期的东西。

但是,您刚才提到的对象更有可能是实体而不是服务,我认为注入不是一个好主意。

于 2014-01-22T22:14:42.580 回答
0

是一个可能有帮助的 IOC 示例。该项目称为 IOC-with-Ninject。它使用 Ninject 和一个 IOC 容器类来管理所有对象的生命周期。您需要对 Ninject 进行一些研究以根据您的特定需求对其进行自定义,但如果您使用的是 .NET,这是您的 IOC 容器解决方案 (IMHO),它将帮助您组织代码库。这是个人选择,但我发誓。如果你不使用 .NET,它仍然会给你一个简单的模式来遵循。干杯。

于 2013-09-10T13:40:58.493 回答
0

根据我的经验,工厂方法效果最好。

控制实例的生命周期对于支持来说很笨重,需要努力、了解所有类的生命周期要求和依赖关系、配置时间和配置管理。同时,工厂的使用是自然的和特定于代码的。

使用代理工厂可以避免创建工厂(实现)。您还可以让工厂返回通用参数,以进一步减少工厂(接口)创建的需求。

如果仍然需要太多工厂,我建议查看代码流。

于 2015-07-28T14:58:33.927 回答
0

我认为这部分是对先前答案的一些评论的重新整理,但我试图举例说明对一些推理的扩展。

一旦进入管理注入对象生命周期的领域,您可能应该为这些对象创建工厂。

根本问题是组合根不知道创建对象所需的调用环境上下文是什么。

我想我应该退后一步,在这一点上解释一下。

关于依赖注入的公认智慧是在代码入口点附近有一个组合根。这有很多很好的理由,在网上不难找到,所以我不会在这里讨论。

组合根是您将接口(通常但可能是对象)映射到它们的实现的地方。您可以将此时可用的信息传递给构造函数。因此,您可以传入一个对象的引用,该对象的生命周期在执行组合根时是当前的。

但是,如果组合根的生命周期与要创建的对象的生命周期不重叠,则必须推迟构造函数的执行,直到需要创建对象。这就是为什么你需要有一个工厂。此时您可以将工厂方法传递给您的映射,从而传递生成对象所需的信息,但允许在需要时进行创建,而不是在执行组合根时。

你不需要工厂类来做这个工厂方法很好,而且工厂方法可以内联,所以代码开销并不比我们在组合路由中创建对象多多少。

如果我们有一个包含 2 个服务的项目,其中第一个服务依赖于第一个服务,并且我们只希望第二个服务的生命周期在我们创建第一个服务时开始,我们可能会有如下内容。(我正在使用 ninject 给出一个代码示例,但我希望其他 IOC 容器在这方面也能类似地工作。)

`   
    公共类Service1:IService
    {
        私有 Func<IService>serviceFactoryMethod _Service2Factory;
        公共服务1(Func<IService>service2FactoryMethod)
        {
            _Service2Factory=service2FactoryMethod;
        }

        公共无效 DoSomethingUsingService2()
        {
            var service2=_Service2Factory();
            service2.DoSomething();
        }
    }

    公共类主类
    {
        公共无效CompositionRoot()
        {
            var kernel= new StandardKernel();
            kernel.Bind.ToMethod(m=>
            {
               return new Service1(m.Kernel.Get<IService2>());
            }
        }
    }

`   

这个例子没有说明你将如何管理应用程序的生命周期、玩家和游戏的生命周期,但希望它能提供足够的线索来说明如何消除与依赖注入相关的生命周期问题。

旁注:使用 Ninject,您将能够更改 Service2 的范围,以便管理其生命周期,使其超出 Service1 的生命周期。例如,如果您知道游戏的每个实例都将在其自己的线程上发生(好吧,这可能不太可能),您可以为游戏使用 InThreadScope。

于 2016-07-05T10:34:03.920 回答