Creating objects with dependencies - dependency injection

前端 未结 3 1313
醉酒成梦
醉酒成梦 2021-01-06 11:21

Let\'s say we have class:

public class WithDependencies
{
  public WithDependencies(IAmDependencyOne first, IAmDependencyTwo second)
  // ...
}
3条回答
  •  一整个雨季
    2021-01-06 11:49

    If you need to create a dependency which has its own dependencies, you can either A) do it yourself, or B) ask something else to do it for you. Option A negates the benefits of dependency injection (decoupling, etc.), so I would say option B is a better starting point. Now, we have chosen to use the factory pattern, no matter whether it takes the form of a service locator (i.e. IoC.Resolve), a static factory, or an instance factory. The point is that we have delegated that responsibility to an external authority.

    There are a number of trade-offs required for static accessors. (I went over them in another answer, so I won't repeat them here.) In order to avoid introducing a dependency on the infrastructure or the container, a solid option is to accept a factory for creating WithDependencies when we need an instance somewhere else:

    public class NeedsWithDependencies
    {
        private readonly IWithDependenciesFactory _withDependenciesFactory;
    
        public NeedsWithDependencies(IWithDependenciesFactory withDependenciesFactory)
        {
            _withDependenciesFactory = withDependenciesFactory;
        }
    
        public void Foo()
        {
            var withDependencies = _withDependenciesFactory.Create();
    
            ...Use the instance...
        }
    }
    

    Next, we can create a container-specific implementation of the factory:

    public class WithDependenciesFactory : IWithDependenciesFactory
    {
        private readonly IContainer _container;
    
        public WithDependenciesFactory(IContainer container)
        {
            _container = container
        }
    
        public WithDependencies Create()
        {
            return _container.Resolve();
        }
    }
    

    Now NeedsWithDependencies is completely isolated from any knowledge of how WithDependencies gets created; it also exposes all its dependencies in its constructor, instead of hiding dependencies on static accessors, making it easy to reuse and test.

    Defining all those factories can get a little cumbersome, though. I like Autofac's factory relationship type, which will detect parameters of the form Func and automatically inject a function which serves the same purpose as the hand-coded factory above:

    public class NeedsWithDependencies
    {
        private readonly Func _withDependenciesFactory;
    
        public NeedsWithDependencies(Func withDependenciesFactory)
        {
            _withDependenciesFactory = withDependenciesFactory;
        }
    
        public void Foo()
        {
            var withDependencies = _withDependenciesFactory();
    
            ...Use the instance...
        }
    }
    

    It also works great with runtime parameters:

    public class NeedsWithDependencies
    {
        private readonly Func _withDependenciesFactory;
    
        public NeedsWithDependencies(Func withDependenciesFactory)
        {
            _withDependenciesFactory = withDependenciesFactory;
        }
    
        public void Foo(int x)
        {
            var withDependencies = _withDependenciesFactory(x);
    
            ...Use the instance...
        }
    }
    

提交回复
热议问题