开发者

How to inject dependencies into classes that implement an interface?

开发者 https://www.devze.com 2023-01-23 16:09 出处:网络
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 inj

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 properti开发者_运维知识库es, but passing them via constructors makes more sense to me. How to DI then ?


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.


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.


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 :-)


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.


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?

0

精彩评论

暂无评论...
验证码 换一张
取 消