business + software { architecture }

affect business outcomes

Dependency Injection - Part 2: Containing Injection

    John Gobble     0

In my first post on DI, I discussed Dependency Injection basics and made the point that, if you aren't practicing DI in your day-to-day design activities, YOU SHOULD BE. In this article I will speak about the glue that is needed in order to make DI a functional and extensible part of your software design.

Putting the Pieces Together

Let's say you've now gone to the effort of pulling concrete dependencies out of your code - forcing the caller to supply them, and you've replaced each dependency with an Interface version of the dependency that specifies, by contract, the portions of that dependency that should be public.

Let's also say that you are designing a 3-tier system (e.g., Presentation, Manager, and Data Access) named Blog, and that you are the creator and consumer of each layer except for the output of presentation.

The output of your dependency chain should look something like the following sample:

Note: I'm using the SyntaxHighlighter library by Alex Gorbatchev to format code samples on this blog.

public class BlogPost {
    public string Title { get; set; }
    public string Body { get; set; }
}

// Blog View Interface and Concrete
public interface IBlogView
{
    void ShowBlogPost();
}

public class BlogForm : IBlogView
{
    private readonly IBlogManager _blogManager;

    public BlogForm(IBlogManager blogManager)
    {
        _blogManager = blogManager;
    }

    public void ShowBlogPost()
    {
        var blogPost = _blogManager.GetBlogPost(1);
        // Display the post...
    }
}

// Blog Manager Interface and Concrete
public interface IBlogManager
{
    BlogPost GetBlogPost(int id);
}

public class BlogManaer : IBlogManager
{
    private readonly IBlogDao _blogDao;

    public BlogManager(IBlogDao blogDao)
    {
        _blogDao = blogDao;
    }

    public BlogPost GetBlogPost(int id)
    {
        return _blogDao.GetBlogPost(id);
    }
}

// Blog Dao Interface and Concrete
public interface IBlogDao
{
    BlogPost GetBlogPost(int id);
}

public class EntityFrameworkBlogDao : DbContext, IBlogDao
{
    public DbSet BlogPosts { get; set; }

    public EntityFrameworkBlogDao(DbConnection dbConnection) : base(dbConnection)
    {
    }

    public BlogPost GetBlogPost(int id)
    {
        return BlogPosts.FirstOrDefault(p => p.Id == id);
    }
}

So our dependency chain looks something like:

BlogForm >>depends on>> IBlogManager >>depends on>> IBlogDao >>depends on>> DbConnection

The Black Box

With our dependencies in place, we now have two questions to answer: What creates my BlogForm, and how does this THING know how to create a concrete version for my IBlogManager dependency and each subsequent dependency in the chain?

Now is when we get to introduce the concept of an Inversion of Control (IoC) Container. The IoC container is responsible for "knowing" by configuration which Interfaces get mapped to which concrete Classes at Compile and Runtime. Once the container has been "configured" with Interface-to-Concrete mappings (also known as bindings), we ask the IoC container for the root node in our chain, which, in our case, is the IBlogView that we would have mapped to the BlogForm. If you are wiring up an IoC container for a thick client app, you would make this first request for the IBlogView in something like a Program.cs class (for those C# folks out there).

Final Thoughts

Although the concept of putting all your Interfaces and Concretes into a Black Box and then requesting the first object and having it and the remaining dependencies just get created is somewhat magical, the concept is fairly straightforward: let something create my dependencies for me when they're needed. This approach allows decoupling of our dependencies from our code and then allows us to request that dependencies be created and given to us through constructor or property injection.

In my next post on IoC Tools, we'll look at a number of common IoC Containers that are available in the marketplace and discuss the types of IoC-created instance scoping that we have available to us (e.g., Transient, Singleton, etc.).


Tags: Dependency Injection, Design, DI, Inversion of Control, IoC

Related posts


New comment


Comments

No comments available.