我一直在使用结构图和放大器依赖IoC模式1年asp.net mvc。 IoC非常简洁,特别是如果你的类中有很多依赖项,只需在构造函数中注入依赖项并完成,IoC会自动为你注入它。
我的问题是我使用asp.net mvc和一个具有IServices依赖关系的控制器类。
我只需要针对某个控制器操作的依赖服务,请说“/ customer / add” 但我不需要那些依赖其他行动的人说“/ Customer / Index”。但是,由于我在构造函数中使用了DI(依赖注入),因此即使我不需要依赖项,也始终实例化依赖项。那有什么好处吗?对象创建很昂贵并且占用内存占用。
当然,我可以在一个动作中执行container.GetInstance,但这不是一个好习惯,因为在代码和单元测试中你会非常依赖IoC。
有什么建议吗?如果我错了什么,请纠正我。
答案 0 :(得分:4)
我总是使用构造函数。 imho属性应该只用于解决循环依赖。
原因是使用属性时意图不明确。您的代码中没有任何内容表明如果未设置属性MyController.DoThat
,则MyController.MyProperty
将无效。
如果方法需要特定服务,那么整个班级都需要该服务。否则,你将违反你的课程所披露的合同。
答案 1 :(得分:4)
更新以回应jgauffins评论
我看到两种直接解决问题的方法:
将服务工厂注入构造函数并按需创建服务。
interface IFooService
{
void Bar();
}
interface IFooServiceFactory
{
IFooService CreateFooService();
}
class YourController
{
public YourController(IFooServiceFactory fooServiceFactory)
{
this.fooServiceFactory = fooServiceFactory;
}
public void YourAction()
{
IFooService fooService = this.fooServiceFactory.CreateFooService();
fooService.Bar();
}
}
将服务代理注入构造函数,让代理按需创建实际服务。
interface IFooService
{
void Bar();
}
class FooServiceProxy : IFooService
{
private IFooService realFooService;
void IFooService.Bar()
{
IFooService realFooService = GetRealFooService();
realFooService.Bar();
}
private IFooService GetRealFooService()
{
if(this.realFooService == null)
{
this.realFooService = CreateRealFooService();
}
return this.realFooService;
}
private IFooService CreateRealFooService()
{
// You could inject the service factory in the constructor of the proxy and use it here to create the real service.
}
}
class YourController
{
Inject FooServiceProxy here
v
v
public YourController(IFooService fooService)
{
this.fooService = fooService;
}
public void YourAction()
{
this.fooService.Bar();
}
}
答案 2 :(得分:3)
即使我不需要依赖项,也始终实例化。那有什么好处吗?
虽然并非该类的每个部分都需要依赖项,但类本身需要该依赖项,因此不是可选的依赖项。通常,当您看到某个部分使用了某个依赖项而其他部分使用了其他依赖项时,您的类可能违反了SRP;它可能不止一件事。然而,拆分它们可能对你没有帮助,因为MVC Controller
类更侧重于接口,所以我只是保持原样。
对象创建很昂贵并且占用内存占用。
引用类型总是有8个字节的开销(在32位平台上),所以这并不多。您通常注入的服务对象确实包含非常少的状态,通常只是一些配置值和对其依赖项的引用。从内存的角度来看,与流经您应用程序的数据(例如来自数据库的数据或MVC生成的用于构建HTML的字符串)相比,它无关紧要。它确实取决于您使用的DI框架,但通常即使是相对较大的依赖图也会在瞬间生成。即使图形构建花费太多时间,还有其他方法可以优化性能。例如,考虑用单身生活方式定义一些服务。如果这还不够,您可能需要考虑切换到更快的DI框架。然而,StructureMap是该领域(更常见的)容器中的faster DI容器之一,因此对于正常的应用程序开发,这应该不是问题。
答案 3 :(得分:1)
我一直这样做的方式是,对于可选的注入依赖项(例如在刚才描述的场景中,只有某些方法需要依赖项),将它们设置为属性即可。对于必需依赖项,请使用构造函数注入。
答案 4 :(得分:0)
StructureMap支持延迟实例化 - 无需制作自己的服务工厂/代理解决方案。如果您只想在使用它的操作中实例化IService
,请在构造函数中注入Func<IService>
。然后,在需要它的操作中,调用Func返回实例。
class CustomerController {
Func<IService> _service;
public CustomerController(Func<IService> service){
_service = service;
}
public ActionResult Index(){
_service().CallMethodOnService();
}
}
但是,在进行额外的工作之前,我首先要确保实例化服务确实是一个性能问题。