Overview:
The dependence inversion principle is dependent on abstraction, not specific. Simply put, we need to program the abstraction rather than the implementation, which reduces the coupling between the customer and the implementation module.
Intent:
For process-oriented development, the upper layer calls the lower layer, and the upper layer depends on the lower layer. When the lower layer changes dramatically, the upper layer also needs to change, this will reduce the reusability of modules and greatly increase the development cost.
Object-Oriented development solves this problem very well. In general, the probability of abstract changes is very small, so that users canProgramThe Implementation Details depend on the abstraction. Even if the implementation details are constantly changing, the customer program will not need to change as long as the abstraction remains unchanged. This greatly reduces the coupling between customer programs and implementation details.
Process-oriented structure:
Figure 1
Background 1: The company is a gold partner of Ford and Honda, and now requires the development of a self-driving system, as long as the system is installed on the car to achieve self-driving, the system can be used in Ford and Honda cars, as long as the two brands of cars use the system to achieve automatic driving. So someone made an analysis.
Figure 1: We define an autosystem class, a fordcar class, And a hondacar class. Fordcar and hondacar have three methods: Run (start car), turn (turn car), stop (Stop car). Of course, a car certainly does not have more than these functions, you only need to explain the problem here. The autosystem class is an autonomous system that automatically operates the two vehicles.
CodeImplementation:
Public class hondacar {public void run () {console. writeline ("Honda started");} public void turn () {console. writeline ("Honda started turning");} public void stop () {console. writeline ("Honda stops ");}}
public class fordcar {public void run () {console. writeline ("Ford started");} public void turn () {console. writeline ("Ford started turning");} public void stop () {console. writeline ("Ford stops") ;}
Public class autosystem {public Enum cartype {Ford, Honda}; private hondacar hcar = new hondacar (); Private fordcar fcar = new fordcar (); Private cartype type; public autosystem (cartype type) {This. type = type;} private void runcar () {If (type = cartype. ford) {fcar. run ();} else {hcar. run () ;}} private void turncar () {If (type = cartype. ford) {fcar. turn ();} else {hcar. turn () ;}} private void stopcar () {If (type = cartype. ford) {fcar. stop ();} else {hcar. stop ();}}}
Code analysis: The above program can indeed achieve self-driving for Ford and Honda vehicles, but the software is constantly changing and the demand for software is constantly changing.
Background 2: The company's business has grown bigger and has become a gold partner of GM, Mitsubishi, and Volkswagen, as a result, the company asked the self-driving system to be installed on the three companies. So we have to change autosystem:
Public class autosystem {public Enum cartype {Ford, Honda, BMW}; hondacar hcar = new hondacar (); fordcar fcar = new fordcar (); bmwcar bcar = new bmwcar (); private cartype type; Public autosystem (cartype type) {This. type = type;} private void runcar () {If (type = cartype. ford) {fcar. run ();} else if (type = cartype. honda) {hcar. run ();} else if (type = cartype. BMW) {bcar. run () ;}} private void turncar () {If (type = cartype. ford) {fcar. turn ();} else if (type = cartype. honda) {hcar. turn ();} else if (type = cartype. BMW) {bcar. turn () ;}} private void stopcar () {If (type = cartype. ford) {fcar. stop ();} else if (type = cartype. honda) {hcar. stop ();} else if (type = cartype. BMW) {bcar. stop ();}}}
Analysis: this will add new dependencies to the system. Over time, more and more vehicle types must be added to autosystem. This "autosystem" module will be messy by the IF/else statement and relies on many lower-layer modules, as long as the lower-layer module changes, autosystem must follow the changes,
It will eventually become rigid and fragile.
One cause of the problem described above is that modules with high-level policies, such as the autosystem module, depend on the specific details of the lower layers it controls (such as hondacar () and fordcar ()). If we can find a way to make the autosystem module independent of the specific details it controls, then we can freely reuse it. We can use this module to generate other programs so that the system can be used in the desired car. Ood provides us with a mechanism to implement this "Dependency inversion ".
Structure:
Figure 2
See the simple class diagram in Figure 2. Here is an "autosystem" class that contains an "ICAR" interface. This "autosystem" class does not depend on "fordcar" or "hondacar" at all ". Therefore, the dependency is "Inverted": the "autosystem" module depends on abstraction, and the specific car operations also depend on the same abstraction.
You can add ICAR
Public interface ICAR {void run (); void turn (); void stop ();}
Public class bmwcar: ICAR {public void run () {console. writeline ("BMW started");} public void turn () {console. writeline ("BMW started turning");} public void stop () {console. writeline ("BMW stopped ");}}
Public class fordcar: ICAR {public void run () {console. writeline ("Ford started");} public void turn () {console. writeline ("Ford started turning");} public void stop () {console. writeline ("Ford stops ");}}
public class hondacar: ICAR {public void run () {console. writeline ("Honda started");} public void turn () {console. writeline ("Honda started turning");} public void stop () {console. writeline ("Honda stops") ;}
Public class autosystem {private ICAR; Public autosystem (ICAR) {This. ICAR = ICAR;} private void runcar () {ICAR. run ();} private void turncar () {ICAR. turn ();} private void stopcar () {ICAR. stop ();}}
Currently, the autosystem system relies on the ICAR abstraction, but it has nothing to do with the specific implementation details, such as hondacar, fordcar, and bmwcar. Therefore, changes in implementation details will not affect autosystem. For implementation details, you only need to implement ICAR. That is, the Implementation Details depend on ICAR abstraction.
To sum up:
Important policy decisions and business models in an application are in these high-level modules. These models also contain the characteristics of applications. However, when these modules depend on the lower-layer modules, modifications to the lower-layer modules will directly affect them and force them to change as well. This situation is ridiculous. It should be a high-level module that forces those lower-level modules to change. A module at the upper level takes precedence over a module at the lower level. A higher-level module should not depend on a lower-level module. What we want to reuse is a high-level module. Through the sub-library form, we can reuse the lower-layer modules very well. When a high-level module depends on a low-level module, it is difficult for these high-level modules to be reused in different environments. However, when higher-level modules are independent of lower-level modules, they can be easily reused. This is the principle at the core of the Framework Design.
Conclusion: Dependency inversion principle
A. High-level modules should not depend on low-level modules. They should all rely on abstraction.
B. abstraction should not depend on specifics, but on abstraction.