Xaqron
Xaqron

Reputation: 30857

How to inject dependencies into classes that implement an interface?

I know interfaces cannot define constructors. What is the best practice to force all classes implementing an interface, to receive their dependencies in a uniform contract. I know ints possible to inject dependencies into objects via properties, but passing them via constructors makes more sense to me. How to DI then ?

Upvotes: 8

Views: 5135

Answers (5)

Stefan
Stefan

Reputation: 91

The interface is not responsible for dependencies. Only the implementation knows, what it needs to fulfill the contract.

There could be one implementation using a database, another using file system to persist data.

Which Dependency should the interface declare required? The database manager or the filesystem manager?

Upvotes: 0

Xaqron
Xaqron

Reputation: 30857

We all know this is possible by many different methods, but something that makes sense is more welcome surely. I defined some set-only properties, then the object is responsible to holding a reference to what is passed to it:

public interface IBlogRepository
{
    ISession Session { set; }
}

class BlogRepository : IBlogRepository
{
   private ISession m_session;

   ISession Session
   {
      set { m_session = value; }
   }
}

This way every class implementing the interface knows that the set-only property is a dependency injection, since set-only properties are rarely used. I'm not sure if this method is known as a good practice or not, but for me it is, from now.

Upvotes: 0

Merlyn Morgan-Graham
Merlyn Morgan-Graham

Reputation: 59111

I know you said you want to have a stable contract. But an advantage to not supplying a stable interface is that your dependencies could then vary wildly with different implementations, which would reduce coupling:

public interface IBlogRepository
{
    IEnumerable<Entry> GetEntries(int pageId, int pageCount);
}

class BlogDatabase : IBlogRepository
{
    public BlogDatabase(ISession session)
    {
        this.session = session;
    }

    public IEnumerable<Entry> GetEntries(int pageId, int pageCount)
    {
        // Not that you should implement your queries this way...
        var query = session.CreateQuery("from BlogEntry");
        return query.Skip(pageId * pageCount).Take(pageCount);
    }

    private ISession session;
}

As you've said, you can also implement dependencies as properties (or arguments), but this will hard-code your dependencies, rather than making them implementation specific. You will decouple your specific session implementations, but you still have to depend on sessions.

public interface IBlogRepository
{
    ISession Session { get; set; }
    IEnumerable<Entry> GetEntries(int pageId, int pageCount);
    IEnumerable<Entry> GetEntriesWithSession(ISession session,
        int pageId, int pageCount);
}

class BlogDatabase : IBlogRepository
{
    public ISession Session { Get; set; }

    public IEnumerable<Entry> GetEntries(int pageId, int pageCount)
    {
        var query = Session.CreateQuery ...
    }

    public IEnumerable<Entry> GetEntries(ISession session, int pageId, int pageCount)
    {
        var query = session.CreateQuery ...
    }
}

class BlogFile : IBlogRepository
{
    // ISession has to abstract a file handle.  We're still okay
    // ...
}

class BlogInMemory : IBlogRepository
{
    // ISession abstracts nothing.
    // Maybe a lock, at best, but the abstraction is still breaking down
    // ...
}

Constructor injection will only work if you're using some sort of Dependency Injection framework that can handle constructing/supplying dependencies for you. Property and argument injection will work even without the framework.

I believe all three are accepted practice. At least a couple popular frameworks support both constructor and property injection.

This means the decision is up to you as to what makes the most sense for your project. The trade-off is a dependency graph that's easy to trace, vs stronger coupling. The decision certainly doesn't have to be all-constructor or all-property/argument, either.

Another higher-level abstraction to think about is an abstract factory class. You'd do this if you want to group a set of dependencies, or you need to construct instances of them at runtime:

public interface IInstallationFactory
{
    IUser CreateRegisteredUser(Guid userSid);
    IPackage CreateKnownPackage(Guid id);
    IInstaller CreateInstaller();
}

Various frameworks also support abstract factories.

Upvotes: 7

Carlo V. Dango
Carlo V. Dango

Reputation: 13832

what you need to do is to have all your interface implementations subclass a class with a constructor taking whatever state that needs be injected. since the subclasses needs to perform a base-call, in their constructor, your constraints are uphold automatically.

at first this may seem like a strange pattern, but we use it all the time in our enterprise solutions, so I guarantee its sane :-)

Upvotes: 2

davisoa
davisoa

Reputation: 5439

One option is to create a method on the interface for initialization. This method can accept all of the required dependencies.

Something like:

void Configure(dependency1 value, etc.);

Of course, there are a lot of options to do this type of initialization and DI using a framework. There are a lot of options to choose from though.

Scott Hanselman has a good list here.

Upvotes: 3

Related Questions