“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”

I. What is the principle of dependence inversion

1.1 concept

Dependence Inversion Principle (DIP)

  1. High-level modules should not depend on low-level modules; both should depend on their abstractions
  2. Abstractions should not depend on details; details should depend on abstractions
  3. Program to interfaces, not implementations

1.2 What is dependency?

The dependencies here are understood as dependencies in UML relationships. A is A use B is A use B is A use B See the example below for details.

From the figure above, we can see that class B is used in method A () of class A. In fact, this is A dependency. A depends on B. Note: it is not A dependency if B is declared in A. If it is referenced but no actual method is called, then it is called zero coupling. The diagram below:

1.3 Types of dependency relationships

1. Zero coupling: If there is no coupling between two classes, it is said to be zero coupling

2. Direct coupling: Concrete coupling occurs between two concrete (instantiable) classes through a direct reference from one class to the other.

3. Abstract coupling: Abstract coupling occurs between a concrete class and an abstract class (or Java interface), allowing maximum flexibility between two classes that must be related.

The principle of dependency inversion is to program to the interface, not the implementation. This means that an interface or abstract class should be used for type declarations of variables, type declarations of parameters, return type declarations of methods, and conversions of data types.

Ii. The case of dependence inversion

2.1 Preliminary design scheme

public class Benz {
    public void run(a) {
        System.out.println("The Mercedes is running!); }}public class Driver {
    private String name;
    public Driver(String name) {
        this.name = name;
    }

    public void driver(Benz benz) { benz.run(); }}public class CarTest {
    public static void main(String[] args) {
        Benz benz = new Benz();
        Driver driver = new Driver("Zhang"); driver.driver(benz); }}Copy the code

There’s a driver zhang SAN who can drive a Mercedes, so initially we thought, there’s going to be a driver class and there’s going to be a Mercedes class. With the development of the business, we found that the driver Zhang SAN can also drive a BMW.

So, let’s define a BM class,

public class BM {
    public void run(a) {
        System.out.println("The BMW is running!"); }}Copy the code

At this point, if Zhang SAN wants to drive a BMW, he has to register it in his name.

public class Driver {
    private String name;
    public Driver(String name) {
        this.name = name;
    }

    public void driver(Benz benz) {
        benz.run();
    }

    public void driver(BM bm) { bm.run(); }}public class CarTest {
    public static void main(String[] args) {
        Benz benz = new Benz();
        BM bm = new BM();
        Driver driver = new Driver("Zhang"); driver.driver(benz); driver.driver(bm); }}Copy the code

It seems like that’s ok, but what’s wrong with that?

  1. If Zhang SAN wants to drive a Volkswagen one day, he will have to add a Volkswagen category, and he will have to carry the driver’s name.
  2. Not everyone is going to drive a Mercedes or a BMW. Open the public.

That’s the problem of implementation oriented programming, and then we’re going to consider interface oriented programming.

2.2 Improved scheme

public interface ICar {
    public void run(a);
}

public class Benz implements ICar{
    public void run(a) {
        System.out.println("The Mercedes is running!); }}public class BM implements ICar{
    public void run(a) {
        System.out.println("The BMW is running!"); }}public interface IDriver {
    public void driver(ICar car);
}

public class Driver implements IDriver{

    @Override
    public void driver(ICar car) { car.run(); }}public class CarTest {
    public static void main(String[] args) {
        IDriver driver = new Driver();
        driver.driver(new Benz());
        driver.driver(newBM()); }}Copy the code

After the modification of the code, extracted an IDriver interface and ICar interface, interface programming. IDriver’s implementation class driver can drive any type of car, so the passed parameter is also an interface ICar. Any type of car can be registered as a new type of car by implementing the ICar interface. When the client calls, the corresponding car will be passed in.

Three. The way of dependence

3.1 There are three methods of DEPENDENCY injection:

Construct injection. Inject dependencies at construct timeCopy the code
  1. Setter method injection
  2. Interface method (the car example uses this method)

3.2 The embodiment of the principle of dependency inversion in the design pattern

  1. The simple factory design pattern uses injection in interface methods
  2. Policy design pattern: Injection in constructors.

Specific usage, you can see the following two articles: A. Simple Factory design patterns: B. Strategy design pattern: