介绍
依赖倒置原则的原始定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象(High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions)。其核心思想是:要面向接口编程,不要面向实现编程。
引用自:http://c.biancheng.net/view/1326.html
好处是:
- 依赖倒置原则可以降低类间的耦合性。
- 依赖倒置原则可以提高系统的稳定性。
- 依赖倒置原则可以减少并行开发引起的风险。
- 依赖倒置原则可以提高代码的可读性和可维护性。
应用场景
对这一原则的理解,可以举个实际项目的例子。
假设需要写一个 bootloader 固件,这个固件支持从 uart, spi, iic 接口进行固件引导。
OK,花了九牛二虎之力,我把 uart, spi, iic 模块都调通了,于是在 bootloader 模块中把这几个模块都引用进来,分别调用其接口并使用判断分支分别进行通讯。代码可能如下:
// bootloader.c
#include "spi.h"
#include "iic.h"
#include "uart.h"
void init(void)
{
spi_init();
iic_init();
uart_init();
}
void write(xxx)
{
if (current_interface == UART) uart_write(xxx);
else if (current_interface == SPI) spi_write(xxx);
else if (current_interface == IIC) iic_write(xxx);
}
然后,某一天,
项目需求变更:增加一个 SDIO 接口。你微微一笑,很快在代码里新增一条判断分支,自信回头;
需求继续变更:uart 口不要了。你眉头一皱,按下“CTRL + F”全局搜索,删除了 uart 相关的代码,然后呼出一口气;
需求无穷尽也:IO 口数量有限,只要 UART 口就好了。。。你拿起手机,按下 553:“老婆,今晚加班”。
应用代码
以上例子,充分说明了“高层模块不应该依赖低层模块,应该依赖其抽象”这句话的重要性。
这里,高层模块指的就是 bootloader.c 模块,而低层模块,则是 spi.c 等这些接口驱动模块。
解决这一问题,我们可以在他们之间增加一个抽象模块:communicate.c,来分割 bootloader.c 对各个接口 .c 的直接依赖。
实现代码如下:
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <windows.h>
/*
依赖倒置原则的示例代码
要面向接口编程,不要面向实现编程。
抽象不应该依赖细节
源码实现目标:
设计一个通讯模块,该模块属于一个 bootloader 固件。
该 bootloader 支持 uart, spi, iic 等通讯接口
抽象是:communicate.c
细节是:iic.c spi.c uar