Coding best practices-dependency injection principles

Source: Internet
Author: User

In the first four articles in this series, we introduced the first four principles in the solid principle. Today we will introduce the last principle-the dependency injection principle. Dependency injection (DI) is a simple concept, and implementation is also very simple. However, simplicity does not cover up its importance. Without dependency injection, the solid technology principles described earlier cannot be applied in practice.

Control inversion (IOC)

When talking about dependency injection, people often talk about another concept-IOC ). According to the explanation of Mr. A, "IOC mainly embodies the following design idea:Transfers control of a set of general processes from the application to the FrameworkTo implementProcess reuseAnd follow the"Hollywood law"Interaction between application code and framework". The concept is abstract. Let's take a look at it.

Everything we need to do can be divided into corresponding steps regardless of the size. Therefore, everything has a fixed process. Like the real-world problem domain, the solution domain (Program Implementation) is the same. Therefore, IOC control can be understood as"Process Control". Taking the process of HTTP request processing as an example, in the traditional era of class library programming, the process of HTTP request processing is firmly controlled in the hands of applications. After the framework is introduced, the control of request processing is transferred to the framework. The difference between a library and a framework is that the former only provides APIs that implement a single function, the latter forms a complete process for orchestrating these single functions for a target task, which is automatically executed under the drive of an engine. In this way, all programs that use this framework can reuse the HTTP request processing process.

In Hollywood, after you submit your resume to the performing arts company, you have to go home and wait. The Performing Arts Company has full control over the entire entertainment project. actors can only passively accept the work of the film company and complete their own performances as needed. "Don't call us. We will call you (Don't call us, we'll call you)." This is the famous Hollywood law.

IOC perfectly embodies this rule, for ASP. net MVC application development, we only need to define the corresponding controller type and view file according to the agreed rules (such as directory structure and name). This is the so-called"Conventions greater than configurations". When ASP. in the process of processing requests, the net MVC Framework defines the corresponding controller type based on the route parameters generated by parsing, and finds the Controller defined by us according to the predefined rules, then it is automatically created and executed. If the definition needs to present a view in the current action method, the framework will find the View File we defined according to the predefined directory conventions, and dynamically compile and execute it. The whole process shows"Framework call Application"Hollywood law.

To put it simply,The IOC process is the process of transferring control of a set of general processes from the application to the framework to achieve reuse of the process.. However, there is a problem that the reverse is only a general process. In a specific scenario, there may be some special processes or process nodes. At this time, you need to customize the process. Customization is generally performed through the extension points reserved by the framework, such as httphandler and httpmodule in ASP. NET, and middleware in ASP. NET core.

As mentioned aboveIOC is a design concept.. Therefore, IOC cannot solve a specific type of problems. However, the design model based on the IOC idea is acceptable. The simplest and most intuitive one isTemplate MethodMode. This mode requires that a reusable workflow or an algorithm composed of multiple steps be defined as a template method, and the steps that constitute the process or algorithm are implemented in the corresponding virtual method, the template method calls these virtual methods according to the predefined process. All these methods are defined in the same class. We can customize the process by deriving the class and rewriting the corresponding virtual method.

Public class templatemethod {// Process Orchestration public void ABCD () {A (); B (); C (); D ();} // step a protected virtual void a () {}// step B protected virtual void B () {}// Step C protected virtual void C () {}// step d protected virtual void D (){}}
Dependency injection (DI)

Dependency injection (DI) is also a model of the architecture in the mind of control reversal. Here, we collectively refer to the provided object as"Service","Target customers"Or"Service instance". In a di-based application, when defining a service type, we directly inject the dependent services in a corresponding way. According to the "interface-oriented programming" principleThe best way to inject is to rely on the service interface instead of implementation.. Correct dependency injection is invisible to the vast majority of project code. They (Register Code) are limited to a very small code range, usually an independent assembly.

When the application starts, the required services are registered globally. Services are generally registered for interfaces. The core purpose of service registration information is to create or provide corresponding service instances based on interfaces during subsequent consumption. According to the Hollywood law, applications only need to define the services they need,Service instance activation and calling are completely completed by the framework.The framework uses an independent container to provide each service instance. The container used by the framework to provide services is calledDi containerIt is also called the "IOC container" by many people ".All di containers comply with the registration, resolution, and release modes..

Three injection methods of dependency Injection

1. constructor Injection

public class TaskService{    private ITaskOneRepository taskOneRepository;    private ITaskTwoRepository taskTwoRepository;    public TaskService(        ITaskOneRepository taskOneRepository,        ITaskTwoRepository taskTwoRepository)        {            this.taskOneRepository = taskOneRepository;            this.taskTwoRepository = taskTwoRepository;        }}

Advantages:

  • The constructor shows the dependency on other classes. At a glance, we can see that this class requires other classes to work.
  • Without the IOC framework, this class can still work (dependency injection for the poor ).
  • Once the object is initialized successfully, the object state must be correct.

Disadvantages:

  • The constructor has many parameters.
  • Some classes require Default constructors, such as the controller class of the MVC Framework. Once constructor injection is used, the default constructor cannot be used.

2. Property Injection

public class TaskService{    private ITaskRepository taskRepository;    private ISettings settings;    public TaskService(        ITaskRepository taskRepository,        ISettings settings)        {            this.taskRepository = taskRepository;            this.settings = settings;        }    public void OnLoad()    {        taskRepository.settings = settings;    }}

Advantages:

  • The dependency can be changed dynamically at any time during the entire lifecycle of an object.
  • Flexible.

Disadvantages:

  • After an object is created, the status of the object before it is configured is incorrect (the dependent instance injected from the constructor can be used throughout the lifecycle of the class, the dependency instances injected by properties can also take effect from an intermediate point in the class life cycle ).
  • It is not intuitive and cannot clearly indicate which attributes are required.

3. Method Injection

public class TaskRepository{    private ISettings settings;    public void PrePare(ISettings settings)    {        this.settings = settings;    }}

Advantages:

  • Flexible.

Disadvantages:

  • Adding a new dependency will destroy the original method signature. If this method has been used by many other modules, it will be very troublesome.
  • Like constructor injection, there are many parameters.

Constructor injection is recommended among the three injection methods. The most important reason is that the service should be independent and self-governed. Even if it is out of the di framework, this service should still work. Constructor injection meets this requirement. Even if it is out of the di framework, it can still manually inject dependent services.

Dependency injection anti-pattern -- service locator

Suppose we need to define a service type C, which depends on two other services A and B, and the corresponding service interfaces of the latter are IA and IB respectively. If the current application has a DI container (container), we can define this service type C in the following two ways.

public class C : IC{    public IA A { get; }    public IB B { get; }    public C(IA a, IB b)    {        A = a;        B = b;    }    public void Invoke()    {        a.Invoke();        b.Invoke();    }}public class C : IC{    public Container Container { get; }    public C(Container container)    {        Container = container;    }    public void Invoke()    {        Container.GetService<IA>().Invoke();        Container.GetService<IB>().Invoke();    }}

On the surface, there is no big difference between the two methods. All solve the coupling problem of dependent services, and turn the dependency on service implementation into the dependency on interfaces. However, the latter method is not the dependency injection mode,Anti-pattern of service Positioner. Because it seems similar to the dependency injection mode, people often ignore the damages it brings to code.

We canWho uses "Di container" and "service locator"To distinguish the two design patterns. Di containers use frameworks rather than applications. service locator uses applications to provide service instances. Sometimes, it is the only way to provide dependency injection hooks.

SoService locator (Anti-pattern of service positioner)What damage does the Code cause?

  1. Because services in containers are registered globally, di containers are static, which leads to static variables and fields in static classes or services.
  2. The service locator exposes the container information. The reason is that the service locator allows the class to retrieve any object, whether or not appropriate. This violates the "Hollywood rules" of dependency injection. We will call you instead of calling us.
  3. The service locator will directly delegate the container instance to parse the instance object, which will lead to the illusion that the service is not dependent. However, services must be dependent. Otherwise, why should we obtain them from the service locator.

Although we have put forward so many criticisms on the anti-pattern of service positioner, it is still very common. Sometimes there is no chance to inject data from the constructor. The only choice is the service locator. After all, it must be better than not injecting dependencies, and it is better than manually constructing injection dependencies.

Summary

Dependency injection (DI) is a model of the architecture in the concept of control reversal (IOC). All di containers comply with the registration, resolution, and release modes. The injection code is usually in an independent assembly. The injection is best based on the Service Interface rather than the implementation. The activation and call of the service instance are completely done by the framework. Constructor injection is recommended in the three injection modes of dependency injection. In addition, when there is no chance of injecting data from the constructor, you can choose the anti-pattern of the Service positioner. The selection mode principle is:The dependency injection mode is better than the reverse mode of the Service positioner, than the manual construction of the injection dependency, and better than the non-injection dependency..

Reference

Dependency injection 1: Control reversal

Dependency injection 2: IOC-based design mode

Dependency injection 3: dependency injection mode

C # agile development practices

Coderfocus

Public Account:

Statement: This article is a summary of the understanding of the bloggers. The level is limited. If not, please correct me. If you think it is good, click the [recommendation] button under the region. Thank you for your support. For reprinting and referencing, please indicate the author and its source.

Coding best practices-dependency injection principles

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.