[dependency reversal principle] of design principle

My cousin asked me to repair her radio, which confused me

Cousin: brother, my computer blue screen crashed 😓

Me: let me show you.

One meal operation

Me: you have two memory modules here, but one of them is broken. I'll unload it now and use the good one for the time being.

Cousin: Wow! Sure enough, that's great 👍 By the way, brother, my father has an 82 year old radio that has been broken for a long time. Can you repair it for him, too?

Me: ha? Well, I won't.

Cousin: why? Computers can do it. How can a small radio embarrass you?

Me: ha ha, because it violates the principle of dependency inversion.

Cousin: huh? What do you mean by that?

Do not rely on high-level modules. High level modules and low-level modules should depend on each other through abstraction. In addition, abstraction should not rely on concrete implementation details. Concrete implementation details depend on abstraction.

As shown in the figure below:

Why is radio difficult to repair?

Because all parts depend on each other, as shown in the figure on the left, any problem may involve other parts, and people who don't understand can't fix it at all. But computers are different, because the motherboard, CPU, memory and hard disk are designed for the interface, as shown in the right figure. No matter which one goes wrong, it can be modified or replaced without affecting other parts.

For example, now we need to realize a pizza shop, which sells cheese pizza, seafood pizza, super supreme and other varieties. It may be easy for us to think that the pizza shop is the upper module, and the specific pizza variety is the lower module. If we draw a diagram of the relationship between the pizza shop and the pizza variety, it should be like this:

Next, let's look at the code implementation:

public class PizzaStore {

    public void cheesePizza() {
        System.out.println("Cheese pizza");
    }

    public void seafoodPizza() {
        System.out.println("seafood pizza ");
    }
    
    public void superSupreme() {
        System.out.println("super supreme ");
    }
}

Let's simulate the upper layer call:

public static void main(String[] args) {
    PizzaStore pizzaStore = new PizzaStore();
    pizzaStore.cheesePizza();
    pizzaStore.superSupreme();
    pizzaStore.seafoodPizza();
}

If the business expansion of the store adds many varieties, then at this time, the code needs to be modified from the bottom implementation to the high-level call.

We need to add pizza varieties in the PizzaStore class, and we also need to add calls in the high-level calls. In this way, after the system is released, it is actually very unstable. Although this example is relatively simple and the modification will not introduce new bug s, the actual project will be much more complex.

Ideally, the code we have written can be "unchanged for ten thousand years", which means that the covered unit tests can not be modified, and the existing behavior can be guaranteed to remain unchanged, which means stability. The impact of any code change is unknown, no matter how simple it seems.

How to reduce the coupling between high-level and low-level code?

For example, in the embryonic period of commodity economy, barter appeared. If you want to buy a mobile phone, the person who sells the mobile phone asks you to exchange a pig, but you don't have a pig in your hand. At this time, you have to find a boss who sells pigs, but he wants you to exchange sheep with him. You also don't have sheep. Continue to find the person who sells sheep

You see, this series of object dependencies has caused a serious coupling disaster. The best way to solve this problem is that both buyers and sellers rely on an abstract - money, which is exchanged through money, which greatly reduces the degree of coupling.

Our current code is that the upper layer directly depends on the lower layer implementation. Now we need to define an abstract IPizza interface to decouple this strong dependence. As shown in the figure below:

Let's take another look at the code:

First define an abstract interface IPizza of Pizza:

public interface IPizza {
    void pizza();
}

Next, there are different kinds of implementation classes:

public class cheesePizza implements IPizza {
    @Override
    public void pizza() {
        System.out.println("Cheese pizza");
    }
}

public class seafoodPizza implements IPizza {
    @Override
    public void pizza() {
        System.out.println("seafood pizza ");
    }
}

public class superSupreme implements IPizza {
    @Override
    public void pizza() {
        System.out.println("super supreme ");
    }
}

At this time, the upper PizzaStore class depends on IPizza interface:

public class PizzaStore {
    public void sellPizza(IPizza p) {
        p.pizza();
    }
}

Next is the upper layer call:

public static void main(String[] args) {
    PizzaStore pizzaStore = new PizzaStore();
    pizzaStore.sellPizza(new cheesePizza());
    pizzaStore.sellPizza(new seafoodPizza());
    pizzaStore.sellPizza(new superSupreme());
}

You see, under this design, no matter how the variety of the pizza shop is expanded, you only need to create an implementation class of the variety without modifying the underlying code. Later, if the business of the pizza shop continues to expand, in addition to selling pizza, it also sells other snacks, drinks and drinks. Similarly, it only needs to abstract the two interfaces of snacks and drinks and drinks respectively, so that the upper layer call can only rely on these interfaces.

summary

The architecture based on abstraction is much more stable than that based on detail.

Therefore, after getting the requirements, we should face the interface programming, first the top-level design, and then design the code structure in detail.

Well, whether each design principle is properly applied should be analyzed according to specific business scenarios.

reference resources

Geek time column "the beauty of design patterns"

Dahua design mode

https://www.jianshu.com/p/c3ce6762257c

https://www.wmyskxz.com/2019/11/18/tan-yi-tan-yi-lai-dao-zhi-yuan-ze/

Keywords: Java Design Pattern

Added by mysterbx on Fri, 25 Feb 2022 05:38:51 +0200