开发者

Best practice in dependency injection

开发者 https://www.devze.com 2023-04-11 04:30 出处:网络
This is a question about how best to do DI, so it\'s not tied to any particular DI/IoC framework because, well, framework should be chosen based on pattern and practice rather than the other way aroun

This is a question about how best to do DI, so it's not tied to any particular DI/IoC framework because, well, framework should be chosen based on pattern and practice rather than the other way around, no?

I'm doing a project where repository has to be injected into services, a service may require multiple repositories and I'm curious about the pros and cons between following approaches:

  1. Inject repositories in service constructor

    public class SomeService : ISomeService
    {
        private IRepository1 repository1;
        private IRepository2 repository2;
    
        public SomeService(IRepository1 repository1, IRepository2 repository2)
        {
              this.repository1 = repository1;
              this.repository2 = repository2;
        }
    
        public void DoThis()
        {
              //Do something with repository1
        }
        public void DoThat()
        {
              //Do something with both repository1 and repository2
        }
    }
    
  2. Inject a custom context class that include everything any service may need but lazy instantiated (the IServiceContext will be a protected field in BaseService)

    public class SomeService : BaseService, ISomeService
    {
        public SomeService(IServiceContext serviceConte开发者_如何学编程xt)
        {
              this.serviceContext= serviceContext;
        }
    
        public void DoThis()
        {
              //Do something with serviceContext.repository1
        }
        public void DoThat()
        {
              //Do something with both serviceContext.repository1 and serviceContext.repository2
        }
    }
    
  3. Inject into methods that need them only

    public class SomeService : ISomeService
    {
        public void DoThis(IRepository1 repository1)
        {
              //Do something with repository1
        }
        public void DoThat(IRepository1 repository1, IRepository2 repository2)
        {
              //Do something with both repository1 and repository2
        }
    }
    

Some pointers would be appreciated, moreover what're the aspects that I should consider in evaluating alternative like these?


The preferred way of injecting dependencies is Constructor Injection.

Method Injection is less ideal, because this will quickly result in having to pass around many dependencies from service to service and it will cause implementation details (the dependencies) to leak through the API (your method).

Both options 1 and 2 do Constructor Injection, which is good. If you find yourself having to inject too many dependencies in a constructor, there is something wrong. Either you are violating the Single Responsibility Principle, or you are missing some sort of aggregate service, and this is what you are doing in option 2.

In your case however, your IServiceContext aggregate service is grouping multiple repositories together. Many repositories behind one class smells like a unit of work to me. Just add a Commit method to the IServiceContext and you will surely have a unit of work. Think about it: don't you want to inject an IUnitOfWork into your service?


The first option seems to be the most natural from a DI perpective. The service class requires both repositories to perform its function, so making them required in order to construct an instance makes sense semantically (and practically).

The second option sounds a bit like Service Location, which is generally considered an anti-pattern (see http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx). In a nutshell, it creates implicit dependencies, where explicit dependencies are always preferred.


I would do either constructor based injection or property based injection. I would not pass in a context that contains the dependencies unless that context is serving some other purpose.

I prefer constructor based injection for required dependencies, as it makes it super easy for the object creation to blow up if something is missing. I got that from here. If you are going to verify that your dependencies are met, then you have to do it with constructor based injection, since there is no way to tell which setter is the last setter to be fired.

0

精彩评论

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

关注公众号