依赖倒置原则(Dependence Inversion Principle)(DIP)
定义
高层模块不应该依赖底层模块,二者都应该依赖其抽象。简单来说,依赖抽象,而不是依赖细节。
意义
面向对象开发过程中,高层模块需要调用下层模块,所以高层模块必然依赖下层模块,一旦下层模块改动,高层模块可能需要跟着改动。依赖倒置原则提出让高层模块依赖下层模块的抽象,而不是依赖下层模块的具体实现。当需求有变且抽象不需要改动时,通常只需要改动下层模块,高层模块不需要变化。这样就可以减少模块之间的耦合性,提高系统稳定性和可维护性,降低程序修改所造成的的风险。
案例讲解
场景:学生读书
不好的设计:
public class Student
{
public string Name { get; set; }
public Student(string name)
{
Name = name;
}
public void Read(ChineseBook book)
{
Console.WriteLine($"学生【{Name}】开始学习");
book.ReadPage();
}
}
public class ChineseBook
{
public void ReadPage()
{
Console.WriteLine("读了一页语文书");
}
}
public class EnglishBook
{
public void ReadPage()
{
Console.WriteLine("读了一页英语书");
}
}
学生刚开始只能够读ChineseBook,后来学生成长了,需要读EnglishBook,这时候我们就要将Student类添加一个重载方法:
public void Read(EnglishBook book)
{
Console.WriteLine($"学生【{Name}】开始学习");
book.ReadPage();
}
这里的Student类和对应的书籍类之间高度耦合。随着学生的成长,可能需要阅读物理、化学、生物等高阶书籍,那么意味着每增加一种书籍,我们就需要改动Student类,让Student类支持阅读对应的书籍,这显然是个愚蠢的设计。
较好的设计:
public class Student
{
public string Name { get; set; }
public Student(string name)
{
Name = name;
}
public void Read(IBook book)
{
Console.WriteLine($"学生【{Name}】开始学习");
book.ReadPage();
}
}
public interface IBook
{
void ReadPage();
}
public class ChineseBook : IBook
{
public void ReadPage()
{
Console.WriteLine("读了一页语文书");
}
}
public class EnglishBook : IBook
{
public void ReadPage()
{
Console.WriteLine("读了一页英语书");
}
}
新建一个IBook接口,让每种书都实现IBook接口,然后Student的Read方法使用IBook作为参数类型。这样,即使是新增其他种类的书,只需要实现IBook接口,都可以被Student阅读,对于Student类来说不需要任何改动,使Student类和具体书籍类完全解耦。这就符合依赖倒置原则的观点:依赖抽象而不应该依赖细节。
心得总结
1.依赖倒置原则基于一个事实:细节通常是多变的,而抽象比较稳定。在定义抽象的时候需要考虑多一点,让后期改动可以不用修改抽象。
2.依赖倒置原则的核心就是让我们面向接口编程。
3.遵循依赖倒置原则时底层模块尽量都要有抽象类或接口,声明变量的类型尽量是抽象类或接口。
4.遵循依赖倒置原则的同时需要注意里氏替换原则。
5.依赖倒置不仅适用于类,也适用于类库。比如:常见的三层架构通常可以将数据层和业务层进行抽象,添加对应的接口层,使UI层和业务层、业务层和数据层完全解耦。
版权声明:本文由不落阁原创出品,转载请注明出处!
广告位
暂无评论,大侠不妨来一发?
跟不落阁,学DOTNET!
广告位