Dependency Injection vs Factory Pattern

2019-01-02 19:03发布

Most of the examples quoted for usage of Dependency Injection, we can solve using the factory pattern as well. Looks like when it comes to usage/design the difference between dependency injection and factory is blurred or thin.

Once someone told me that its how you use it that makes a difference!

I once used StructureMap a DI container to solve a problem, later on I redesigned it to work with a simple factory and removed references to StructureMap.

Can anyone tell me what is the difference between them and where to use what, whats the best practice here?

27条回答
路过你的时光
2楼-- · 2019-01-02 19:21

There are problems which are easy to solve with dependency injection which are not so easily solved with a suite of factories.

Some of the difference between, on the one hand, inversion of control and dependency injection (IOC/DI), and, on the other hand, a service locator or a suite of factories (factory), is:

IOC/DI is a complete ecosystem of domain objects and services in and of itself. It sets everything up for you in the way you specify. Your domain objects and services are constructed by the container, and do not construct themselves: they therefore do not have any dependencies on the container or on any factories. IOC/DI permits an extremely high degree of configurability, with all the configuration in a single place (construction of the container) at the topmost layer of your application (the GUI, the Web front-end).

Factory abstracts away some of the construction of your domain objects and services. But domain objects and services are still responsible for figuring out how to construct themselves and how to get all the things they depend on. All these "active" dependencies filter all the way through all the layers in your application. There is no single place to go to configure everything.

查看更多
只若初见
3楼-- · 2019-01-02 19:22

I had the same question as soon as I read about DI and ended up at this post. So finally this is what I understood but please correct me if am wrong.

"Long ago there were little kingdoms with their own governing bodies controlling and taking decisions based on their own written rules. Later on formed a big government eliminating all these little governing bodies which has one set of rules(constitution) and are implemented through courts"

The little kingdoms' governing bodies are "Factories"

The big government is the "Dependency Injector".

查看更多
柔情千种
4楼-- · 2019-01-02 19:24

Life cycle management is one of the responsibilities dependency containers assume in addition to instantiation and injection. The fact that the container sometimes keep a reference to the components after instantiation is the reason it is called a "container", and not a factory. Dependency injection containers usually only keep a reference to objects it needs to manage life cycles for, or that are reused for future injections, like singletons or flyweights. When configured to create new instances of some components for each call to the container, the container usually just forgets about the created object.

From: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html

查看更多
临风纵饮
5楼-- · 2019-01-02 19:24

With a factory you can group related interfaces, So If the parameters passed can be grouped in a factory then its also a good solution for constructor overinjection look at this code *):

public AddressModelFactory(IAddressAttributeService addressAttributeService,
        IAddressAttributeParser addressAttributeParser,
        ILocalizationService localizationService,
        IStateProvinceService stateProvinceService,
        IAddressAttributeFormatter addressAttributeFormatter)
    {
        this._addressAttributeService = addressAttributeService;
        this._addressAttributeParser = addressAttributeParser;
        this._localizationService = localizationService;
        this._stateProvinceService = stateProvinceService;
        this._addressAttributeFormatter = addressAttributeFormatter;
    }

Look at the constructor, you only have to pass the IAddressModelFactory there, so less parameters *):

 public CustomerController(IAddressModelFactory addressModelFactory,
        ICustomerModelFactory customerModelFactory,
        IAuthenticationService authenticationService,
        DateTimeSettings dateTimeSettings,
        TaxSettings taxSettings,
        ILocalizationService localizationService,
        IWorkContext workContext,
        IStoreContext storeContext,
        ICustomerService customerService,
        ICustomerAttributeParser customerAttributeParser,
        ICustomerAttributeService customerAttributeService,
        IGenericAttributeService genericAttributeService,
        ICustomerRegistrationService customerRegistrationService,
        ITaxService taxService,
        CustomerSettings customerSettings,
        AddressSettings addressSettings,...

You see in CustomerController a lot of parameters passed, Yes you can see this as constructor overinjection but this is how DI works. And no nothing is wrong with the CustomerController.

*) Code is from nopCommerce.

查看更多
闭嘴吧你
6楼-- · 2019-01-02 19:26

I think these are orthogonal and can be used together. Let me show you an example I recently came across at work:

We were using the Spring framework in Java for DI. A singleton class (Parent) had to instantiate new objects of another class (Child), and those had complex collaborators:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

In this example, Parent has to receive DepX instances only to pass them to the Child constructor. Problems with this:

  1. Parent has more knowledge of Child than it should
  2. Parent has more collaborators than it should
  3. Adding dependencies to Child involves changing Parent

This is when I realized a Factory would fit here perfectly:

  1. It hides all but the true parameters of the Child class, as seen by Parent
  2. It encapsulates the knowledge of creating a Child, which can be centralized in the DI configuration.

This is the simplified Parent class and the ChildFactory class:

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}
查看更多
素衣白纱
7楼-- · 2019-01-02 19:27

Most answers here explain conceptual difference and implementation details of both. However I was unable to find explanation about difference in application which IMO is the most important and the OP asked about. So let me reopen this topic...

Once someone told me that its how you use it that makes a difference!

Exactly. In 90% cases you can obtain object reference using either Factory or DI and usually you end up with latter. In another 10% cases using Factory is only correct way. These cases include obtaining objects by variable at runtime parameters. Like this:

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

In this case getting client from DI is not possible (or at least requires some ugly workaround). So as a general rule to make decision: if a dependency can be obtained without any runtime calculated parameters then DI is preferred, otherwise use Factory.

查看更多
登录 后发表回答