对象生命周期管理和IoC容器

时间:2012-11-17 16:46:50

标签: dependency-injection inversion-of-control

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

既然不止一个玩家可以一次玩,我显然需要支持创建多个Player对象,GameState对象等。在这个过程中,我逐渐意识到大多数对象都有三个生命之一:

  1. 应用程序的生命周期,例如一个处理导航的指挥
  2. 玩家的生命周期,例如当前播放器的SettingsViewModel
  3. 游戏的生命周期,例如当前游戏的GameState
  4. 我很好奇其他人如何使用IoC容器处理这些不同对象的创建。我想避免为玩家或游戏生命周期的每个类创建工厂类。

4 个答案:

答案 0 :(得分:0)

Here是IOC可能有所帮助的一个例子。该项目名为IOC-with-Ninject。它使用Ninject加上一个IOC容器类来管理所有对象的生命周期。您需要做一点research on Ninject来根据您的特定需求进行自定义,但如果您使用.NET,这将是您的IOC容器解决方案(恕我直言),并将帮助您组织代码库。这是个人选择,但我发誓。如果您不使用.NET,它仍然会为您提供一个简单的模式。欢呼声。

答案 1 :(得分:0)

许多IoC容器都有自定义生命周期范围,您可以根据需要进行管理。例如,在Ninject中,您可以按如下方式定义自定义生命周期范围:

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

只要yourCustomeScope变量未更改,每次内核收到IService请求时,都会返回一个Service对象实例。只要yourCustomeScope变量发生更改,就会在下一次IService请求时创建一个新的Service实例。 yourCustomeScope可以是当前的播放器实例,游戏对象或您希望根据其参考更改来更改Service对象生命周期的任何内容。

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

答案 2 :(得分:0)

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

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

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

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

答案 3 :(得分:0)

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

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

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

我想我应退后一步并在此时解释。

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

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

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

您不需要工厂类来执行此工厂方法很好,而且工厂方法可以内联,因此代码开销不会比我们在合成路径中创建对象多。

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


`   
    public class Service1:IService
    {
        private Func<IService>serviceFactoryMethod _Service2Factory;
        public Service1(Func<IService>service2FactoryMethod)
        {
            _Service2Factory=service2FactoryMethod;
        }

        public void DoSomethingUsingService2()
        {
            var service2=_Service2Factory();
            service2.DoSomething();
        }
    }

    public class MainClass
    {
        public void CompositionRoot()
        {
            var kernel= new StandardKernel();
            kernel.Bind.ToMethod(m=>
            { 
               return new Service1(m.Kernel.Get<IService2>());
            }
        }
    }

`   

此示例并未说明如何管理应用程序,玩家和游戏生命周期的生命周期,但希望它能提供足够的线索来解决如何消除与依赖注入相关的生命周期问题。

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

相关问题