我正在尝试使用IoC /依赖注入,同时编程为契约而不是特定的类。我所面临的两难境地是:
之间的紧张关系为IoC接口编程:我开始时IoC严重依赖接口。从Spring的示例项目来看,接口是在编写与IoC签订合同时的方法。
( ...虽然通常首选抽象类:the main drawback of interfaces is that they are much less flexible than classes when it comes to allowing for evolution of APIs)
通过构造函数使类依赖项显式化 我的直觉是,将依赖项传递给类的构造函数是一种很好的编程习惯。实际上,这个是依赖注入。
...除非您不能在接口/抽象语句中强制执行构造函数签名:接口或抽象类都不允许定义构造函数签名( easily / elegantly )。 另请参阅Framework Design Guidelines section 4.4: 不要以抽象类型定义公共或受保护的内部构造函数。 ...仅当用户需要创建该类型的实例时,构造函数才应公开。
此问题与之前的stackoverflow问题有关:Interface defining a constructor signature?
但我的问题是:
由于您无法在C#接口/抽象类中定义构造函数,正如上面的问题所要求的那样,在实际层面上:
您如何将此与passing dependencies in via a constructor 的合理做法相协调?
编辑:谢谢你的回答。我希望在这种情况下能够了解我应该做什么。只是不使用contructor args?使用某种确实采用依赖关系的Init()方法? 编辑2:谢谢你的答案,非常有帮助。
答案 0 :(得分:8)
我一直认为使用(制作)示例更容易解释......
想象一下,您有一个ICustomerRepository接口,一个IShoppingCartRepository接口和一个ICheckout接口。您具有这些接口的具体实现 - CustomerRepository,ShoppingCartRepository和CheckoutService。
您的CheckoutService具体类有一个构造函数,它接受一个ICustomerRepository和一个IShoppingCartRepository - 例如。
public CheckoutService(ICustomerRepository customerRepository, IShoppingCartRepository shoppingCartRepository)
{
// Set fields for use in some methods later...
_customerRepository = customerRepository;
_shoppingCartRepository = shoppingCartRepository;
}
然后,当你想要一个ICheckoutService实现做一些工作时,你告诉你的IoC容器它应该为每个接口类型使用哪个具体类,并要求它为你构建一个ICheckoutService。您的IoC容器将为您构建您的类,将正确的具体类注入CheckoutService的构造函数中。它也会在这里继续在类heirarchy中构建依赖关系,所以如果你的ShoppingCartRepository在构造函数中使用了一个IDatabaseSession接口,你的IoC容器也会注入该依赖,只要你告诉它使用哪个具体的类。为您的IDatabaseService。
以下是配置(例如)StructureMap作为IoC容器时可能会使用的一些代码(通常在应用启动期间调用此代码):
public class AppRegistry : Registry
{
public AppRegistry()
{
ForRequestedType<ICheckoutService>().TheDefaultIsConcreteType<CheckoutService>();
ForRequestedType<ICustomerRepository>().TheDefaultIsConcreteType<CustomerRepository>();
// etc...
}
}
然后,为了获得ICheckoutService的一个实例,并准备好了,将所有依赖项传递给构造函数,你可以使用类似的东西:
var checkoutService = ObjectFactory.GetInstance<ICheckoutService>();
我希望这是有道理的!
答案 1 :(得分:1)
您的IoC容器必须从具体类型构造一个对象,即使您传递的是一个接口。您的构造函数不是行为或州合同,因此它不属于接口或抽象类的公共成员。
构造函数是一个实现细节,因此您无需将其定义与具体类分开。
答案 2 :(得分:0)
您无法在接口中定义构造函数签名。这无论如何都没有意义,因为接口不应该强制实现如何构造。
抽象类虽然确实可以有构造函数。他们必须得到保护,因为公共建设者也没有意义。它们只能由具体的子类调用。
IoC原则规定,不要让A类知道并实例化B类,而应该将对IB的引用传递给A的构造函数。然后A不需要知道B类,因此您可以轻松地将B类替换为IB的其他实现。
由于您传入的是已经实例化的B类对象,因此IB接口不需要具有构造函数签名。