我经常读到国际奥委会中的服务定位器是一种反模式。。
去年,我们在我们的应用程序中引入了IOC (具体来说是Ninject)。这个应用程序是遗留下来的,它很大,而且很分散。有很多方法可以创建一个类,或者一个类链。有些是由web框架创建的(这是自定义的),有些是由nHibernate创建的。很多东西都散落在奇怪的地方。
我们将如何处理不同的场景,而不想出至少不是ServiceLocatorish的东西,也不会在不同的地方得到不同的内核(单例、HttpRequest和线程这样的作用域很重要)。
编辑,我将添加一些更多的细节来引导我们找到当前的SL模式。
实际上我们不想要多个内核。我们只想要一个(事实上,由于SL,我们只有一个静态的)。这是我们的设置:
( 1)我们在7-8个不同的项目/组件中有Ninject模块。当我们的应用程序( webapp)启动时,这些模块通过程序集扫描收集,加载到内核中,并放置在Service中。所以这一切都相当昂贵。
2)我们有一个自定义UI框架,它的构造是愉快的。想象一下大约120个选项卡表单,每个表单构建1-10个选项卡页,作为其生命周期的一部分。SL被战略性地应用于5-6个地方,这些地方涵盖了所有这些,要么作为纯解析,要么只在属性的实例化后注入。
3) UI中的任何内容都不包括在顶级调用中,如果这些类想要使用IOC,那么它们需要提出自己的策略。有各种不同的小框架,它们都是各自的小世界。
因此,从我所读到的内容来看,理想的方法是在需要访问IOC...well时注入内核,这一切都很好;我们确实将SL的使用保持在最低限度。
但是我从哪里得到这个内核呢?我不想到处建造和注册一个新的。似乎我必须将其从静态上下文或工厂中删除,这样我就可以确保我所使用的内核保留与其他人使用的作用域相同的对象,并避免注册所有模块的费用。在这一点上,不管那个东西是什么,看起来都很像一个服务定位器,对吗?
请记住,这个应用程序是巨大的,紧密耦合。我们不可能一次花上几个月的时间来重构它。对我们来说,SL似乎是一种很好的方式,可以像我们有时间一样慢慢地在国际奥委会工作。
发布于 2011-07-05 17:21:43
因此,从我所读到的内容来看,理想的方法是在需要访问IOC...well时注入内核,这一切都很好;我们确实将SL的使用保持在最低限度。
不,将内核注入您的业务类并不是最好的方法。更好的方法是创建一个工厂,例如IFooFactory { IFoo Create(); }或Func<IFoo>,并让这个工厂创建新实例。
这个接口的实现进入复合根,获取内核的一个实例,并使用内核进行解析。这使您的类不受特定容器的限制,并且可以使用不同的容器在另一个项目中重用它们。如果使用Func,您可以使用以下模块:Ninject支持Func (自动生成工厂)吗? Ninject 2.4将对此提供本机支持。
就重构而言,在不了解应用程序的源代码的情况下,很难告诉您什么是最好的方法。我可以给你一个可能有用的方法。
我想,从长远来看,您希望将整个应用程序重构为正确的DI。我曾为一个相当大的项目(30-40年)做过一次,内容如下:
从复合根目录开始,并绘制对象树,然后一个接一个地更改一个类,以使用正确的DI。一旦您到达所有leafs,就开始重构所有不依赖于其他服务的服务,并使用相同的方法对它们的leafs进行工作。然后,继续只依赖于已经重构的服务的服务,然后重复,直到所有服务都被重构。所有这些步骤都可以一个接一个地完成,这样代码就可以不断地改进,同时仍然可以添加新的特性。同时,ServiceLocation是可以接受的,只要重点是尽快正确地完成它。
伪代码示例:
Foo{ ServiceLocator.Get<Service1>(), new Bar() }
Bar{ ServiceLocator.Get<IService1>(), ServiceLocator.Get<IService2>(), new Baz() }
Baz{ ServiceLocator.Get<IService3>() }
Service1 { ServiceLocator.Get<Service3>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { new SomeClass()}步骤1-更改根(Foo)
Foo{ ctor(IService1, IBar) }
Bar{ ServiceLocator.Get<IService1>(), ServiceLocator.Get<IService2>(), new Baz() }
Baz{ ServiceLocator.Get<IService3>() }
Service1 { ServiceLocator.Get<IService2>() }
Service2 { ServiceLocator.Get<IService3>() }
Service3 { new SomeClass()}
Bind<IBar>().To<Bar>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());步骤2-更改根的依赖项
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ServiceLocator.Get<IService3>() }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { new SomeClass()}
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().ToMethod(ctx => ServiceLocator.Get<IService2>());步骤3-更改它们的依赖项并继续,直到您到达leafs。
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { new SomeClass() }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().ToMethod(ctx => ServiceLocator.Get<IService2>());
Bind<IService3>().ToMethod(ctx => ServiceLocator.Get<IService3>());步骤4-重构不依赖其他服务的服务
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { ctor(ISomeClass) }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<ISomeClass>().To<SomeClass>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().ToMethod(ctx => ServiceLocator.Get<IService2>());
Bind<IService3>().To<Service3>().InSingletonScope();步骤5-下一步重构那些依赖于仅将重构的服务作为依赖项的服务。
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ctor(IService3) }
Service3 { ctor(ISomeClass) }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<ISomeClass>().To<SomeClass>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().To<Service2>().InSingletonScope();
Bind<IService3>().To<Service3>().InSingletonScope();步骤6-重复,直到每个服务都被重构。
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ctor(IService2) }
Service2 { ctor(IService3) }
Service3 { ctor(ISomeClass) }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<ISomeClass>().To<SomeClass>();
Bind<IService1>().To<Service1>().InSingletonScope();
Bind<IService2>().To<Service2>().InSingletonScope();
Bind<IService3>().To<Service3>().InSingletonScope();您可能希望切换到基于约定的容器配置以及重构。在本例中,我将向所有重构类添加一个属性,以标记它们,并在所有重构完成后再次删除它。在约定中,可以使用此属性对所有重构类进行筛选。
https://stackoverflow.com/questions/6562872
复制相似问题