4

我正在尝试使用依赖注入方法(使用 Ninject)开发一个库,但由于我的设计不正确,我可能会遇到某种混乱。总之,我的设计方法是

  1. 一个parent对象有一个common对象。
  2. 一个parent对象使用一些可变数量的child对象。
  3. 所有child对象都应使用common与其parent对象完全相同的对象实例

这是我的问题域的简单模型。

interface IParent : IDisposable {
    void Operation();
}
interface ICommon : IDisposable {
    void DoCommonThing();
}
interface IChild1 {
    void DoSomething();
}
interface IChild2 {
    void DoAnotherThing();
}
class Parent : IParent {
    private readonly ICommon _common;
    public Parent(ICommon common) {
        _common = common;
    }
    public void Dispose() {
        _common.Dispose();
    }
    public void Operation() {
        var c1 = ObjectFactory.GetInstance<IChild1>();
        c1.DoSomething();
        var c2 = ObjectFactory.GetInstance<IChild2>();
        c2.DoAnotherThing();
        // number of childs vary, do things until cn
        _common.DoCommonThing();
    }
}
class Common : ICommon {
    private bool _isDisposed;
    public void Dispose() {
        _isDisposed = true;
    }
    public void DoCommonThing() {
        if (_isDisposed) 
            throw new Exception("Common Object is Disposed");
    }
}
class Child1 : IChild1
{
    private readonly ICommon _common;
    public Child1(ICommon common) {
        _common = common;
    }
    public void DoSomething() {
        // Do Something...
        _common.DoCommonThing();
    }
}
class Child2 : IChild2 {
    private readonly ICommon _common;
    public Child2(ICommon common) {
        _common = common;
    }
    public void DoAnotherThing() {
        // Do Another Thing...
        _common.DoCommonThing();
    }
}

问题 1

所需child对象的数量各不相同。例如,根据c1.DoSomethingI 的返回值可能需要也可能不需要其他子对象。所以我不想通过构造函数注入它们,只是在需要时创建它们。但这种做法违反了好莱坞原则。

问题 1

在不通过构造函数注入子对象的情况下,如何防止这种违规行为?

问题 2

我希望child对象使用与其对象相同common的对象实例parent。所以common对象的生命周期应该和它的父对象一样。

  1. 如果没有为 ICommon 定义生命周期,那么所有child对象都将拥有自己的common对象实例。

  2. 如果 ICommon 的生命周期是在 Thread 或 Request 范围内定义的,那么我不能parent在同一 Thread 或 Request 范围内使用不同的对象实例。因为每个parent对象都应该使用自己的全新common对象并处理它。

所以我无法使用我知道的生命周期范围选项来解决它。我为第二个问题提出了另一种解决方案,但它使代码变得更糟。

首先,它不是注入ICommonparent对象中,parent而是通过它自己创建的对象ObjectFactory

class Parent : IParent {
    private readonly ICommon _common;
    public Parent() {
        _common = ObjectFactory.GetInstance<ICommon>();
    }
.....

然后,对象不是注入ICommon对象child,而是parent设置common子对象的对象。

interface IChild {
    ICommon Common { get; set; }
}
interface IChildN : IChild {
     void DoNthThing();
}
abstract class ChildBase : IChild {
    ICommon IChild.Common { get; set; }
}
class ChildN : IChildN {
     public void DoNthThing() { }
}
class Parent : IParent {
    private readonly ICommon _common;
    public void Operation() {
        var c1 = ObjectFactory.GetInstance<IChild1>();
        c1.Common = _common;
        c1.DoSomething();
        var c2 = ObjectFactory.GetInstance<IChild2>();
        c2.Common = _common;
        c2.DoAnotherThing();
        _common.DoCommonThing();
    }
}

但是这个解决方案再次违反了好莱坞原则,我必须设置每个child对象的 Common 属性。

问题2

对象如何使用依赖注入parent将其common对象分发给对象?child(最好使用 Ninject)

问题 3

关于我的问题,这有点笼统:如何将依赖注入正确应用于此模型?

注意:Ninject 的ObjectFactory.GetInstance调用Kernel.Get

4

1 回答 1

3

您需要使用CallScopeNamedScope。这些是Ninject.Extensions.NamedScope包装的一部分。这允许您将公共对象的范围限定为父对象,以便所有子请求都接收相同的公共对象。

关于子对象的创建。如果您必须根据某些算法请求子对象,则需要使用工厂对其进行实例化。使用Ninject.Extensions.Factory包来实现这一点。这会保留获取上下文并将父上下文传递给子请求,因此允许在工厂创建的子项中重用您的公共对象。

所以最终将不需要使用你自己的对象工厂。

于 2013-01-29T06:33:31.213 回答