依赖倒置原则 (Dependency Inversion Principle)
flyfish
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.
A.高层模块不应该依赖于低层模块,他们都应该依赖于抽象。
B.抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
按照原则的做法设计一个类结构,该类的结构从高层模块开始到低层模块是这样的。
High Level Classes –> Abstraction Layer –> Low Level Classes
解释:
低层模块:举例 实现基本和主要操作的类(磁盘访问、网络协议等)
高层模块:封装复杂的逻辑(业务流等)
让我们来看一个经典的例子,一个拷贝模块,它从键盘上读取字符并将其写入打印机设备。
包含逻辑的高层模块类是Copy类。低层模块类是KeyboardReader和PrinterWriter。
在糟糕的设计中,高层模块类直接使用,并且很大程度上依赖于低层模块类。在这种情况下,如果我们想要更改设计,将
输出到一个新的FileWriter类中,那么我们必须在Copy类中进行更改。
(让我们假设它是一个非常复杂的类,有很多逻辑,并且很难进行测试,类似log可以输出到屏幕,文件,远程计算上等)
为了避免这些问题,我们可以在高层模块类和低层模块类之间引入一个抽象层。由于高层模块包含复杂的逻辑,所以它们
不应该依赖于低层模块,所以新的抽象层不应该基于低层模块创建。低层模块基于抽象层创建。两边都依赖于抽象层。
// Dependency Inversion Principle - Bad example
class Worker
{
public:
void work()
{
// ....working
}
};
class Manager
{
private:
Worker worker;
public:
void setWorker(Worker w)
{
worker = w;
}
void manage()
{
worker.work();
}
};
class SuperWorker
{
public:
void work()
{
//.... working much more
}
};
好的例子
下面的代码支持依赖倒置原则。在这个新设计中,通过IWorker接口添加了一个新的抽象层。现在,上述代码的问题得到了解决(考虑到高层逻辑中没有变化):
// Dependency Inversion Principle - Good example
class IWorker
{
public:
void work() {}
};
class Worker :public IWorker
{
public:
void work()
{
// ....working
}
};
class SuperWorker :public IWorker
{
public: void work()
{
//.... working much more
}
};
class Manager
{
private:
IWorker worker;
public:
void setWorker(IWorker w)
{
worker = w;
}
void manage()
{
worker.work();
}
};