代码之家  ›  专栏  ›  技术社区  ›  Jeffrey Knight

通过构造函数在IOC中强制依赖?

  •  9
  • Jeffrey Knight  · 技术社区  · 15 年前

    我试图在使用IOC/Dependency注入的同时将编程收缩,而不是特定的类。我面临的困境是:

    1. 为国际奥委会做接口计划 :我从IOC开始,非常依赖接口。从Spring的示例项目来看,在编程与IOC签订合同时,接口是可行的方法。

    2. ( …尽管抽象类通常更受欢迎 : the main drawback of interfaces is that they are much less flexible than classes when it comes to allowing for evolution of APIs )

    3. 通过构造函数使类依赖关系显式化 我的直觉是,将依赖项传递给类的构造函数是一种很好的编程实践。确实如此 依赖注入。

    4. …但不能在接口/抽象类中强制构造函数签名 :接口或抽象类都不允许定义构造函数签名 ( easily / elegantly ) . 也见 Framework Design Guidelines section 4.4: 在抽象类型中定义公共或受保护的内部构造函数。…只有当用户需要创建该类型的实例时,构造函数才应该是公共的。

    此问题与上一个StackOverflow问题相关: Interface defining a constructor signature?

    但我的问题是:

    因为您不能在C接口/抽象类中定义构造函数,正如上面的问题所要求的那样,在实际级别上:

    你如何使这与 passing dependencies in via a constructor ?

    编辑:谢谢你的回答。我希望能对我的工作有所了解 应该 在这种情况下。只是不使用contractor args?使用某种类型的init()方法来获取依赖项? 伊迪丝2:谢谢你的回答,非常有帮助。

    3 回复  |  直到 15 年前
        1
  •  8
  •   Steve Willcock    15 年前

    我一直认为用一个(虚构的)例子来解释这件事比较容易…

    假设您有一个icustomerepository接口、一个ishoppingcartpository接口和一个icheckout接口。您有这些接口的具体实现——customerrepository、shoppingcartreository和checkoutservice。

    您的checkoutServiceConcrete类有一个构造函数,该构造函数接受ICustomerRepository和IShoppingCartPository,例如

    public CheckoutService(ICustomerRepository customerRepository, IShoppingCartRepository shoppingCartRepository)
    {
      // Set fields for use in some methods later...
      _customerRepository = customerRepository;
      _shoppingCartRepository = shoppingCartRepository;
    }
    

    然后,当您希望ICheckOutService实现进行一些工作时,您可以告诉IOC容器它应该为每个接口类型使用哪个具体类,并要求它为您构建一个ICheckOutService。您的IOC容器将为您构建类,并将正确的具体类注入到您的checkoutService的构造函数中。它还将在这里沿着类继承关系一直构建依赖关系,因此,例如,如果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>();
    

    我希望这是有道理的!

        2
  •  1
  •   Michael Meadows    15 年前

    您的IOC容器必须从具体类型构造一个对象,即使您传递的是一个接口。构造函数不是行为或状态协定,因此它不属于接口或抽象类的公共成员。

    构造函数是一个实现细节,因此不需要将其定义与具体类分离。

        3
  •  0
  •   Peter Lillevold Rene    15 年前

    不能在接口中定义构造函数签名。这无论如何都没有意义,因为接口不应该强制实现的构造方式。

    不过,抽象类确实可以有构造函数。它们必须受到保护,因为公共构造函数也没有意义。它们只能由具体的子类调用。

    IOC原则规定,不要让类A知道并实例化类B,而是应该将对ib的引用传递给a的构造函数。这样,a就不需要知道类B,因此您可以很容易地用一些其他的ib实现来替换类B。

    因为您传递的是已经实例化的类B对象,所以ib接口不需要有构造函数签名。