Question

I am trying to develop a library using dependency injection approach (with Ninject) and I am having some kind of confusion likely because of my incorrect design. In summary, my design approach is

  1. A parent object has a common object.
  2. A parent object uses some variable number of child objects.
  3. All child objects should use the very same common object instance with their parent object

Here is a simple model of my problem domain.

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();
    }
}

Problem 1

Number of needed child objects vary. For example, according to return value of c1.DoSomething I may or may not need other child objects. So I do not want to inject them through constructor and just create them when they are needed. But this approach causes violation of Hollywood Principle.

Question 1

How this violation can be prevented, without injecting child objects through constructor?

Problem 2

I want child objects to use same common object instance with their parent object. So life time of common object should be same as its parent.

  1. If there is no life time is defined for ICommon then all child objects will have their own common object instance.

  2. If life time of ICommon is defined in Thread or Request scope then I cannot use different instances of parent object in same Thread or Request scope. Because each parent object should use their own brand new common object and dispose it.

So I could not solve it using life time scope options that I know. I produced another solution for this second problem but it makes code worse.

First, instead of injecting ICommon into parent object, parent object it self creates it through ObjectFactory

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

Then, instead of injecting ICommon into child object, parent object sets common object of child objects.

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();
    }
}

But this solution violates Hollywood Principle again and I have to set Common property of each child object.

Question 2

How can parent object distribute its common object to child objects using Dependency Injection? (preferably with Ninject)

Question 3

This is a little bit more general about my problem: How can Dependency Injection applied correctly to this model?

NOTE: ObjectFactory.GetInstance calls Kernel.Get of Ninject

Was it helpful?

Solution

You need to use either the CallScope or the NamedScope. These are part of the Ninject.Extensions.NamedScope package. This allows you to scope the common object to the parent so all child requests receive the same common.

Regarding the child object creation. If you have to request child objects depending on some algorithm you need to instantiate it with a factory. Use the Ninject.Extensions.Factory package to achieve this. This does a context preserving get and passes the parent context to the child request and therefore allows to reuse your common object also in the children which are created by the factory.

So in the end there will be no need to use your own object factory.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top