当前位置: 首页 > news >正文

设计模式—依赖倒置原则(DIP)

1.概念

依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

通俗的讲:

  1. 要面向抽象编程,而不是面向细节编程;

  2. 高层模块不应该依赖底层模块,二者应该通过抽象依赖,而不是依赖细节;

  3. 抽象不应该依赖于具体,具体应该依赖于抽象。

2.案例分析

需求:我们要开发一套自动驾驶系统,只要在汽车上安装该系统就可以实现自动驾驶,该系统目前只支持在福特和本田车上使用。

优化前版本(不满足依赖倒置原则):

/// <summary>/// 福特车/// </summary>public class FordCar{public void Run(){Console.WriteLine("福特开始启动了");}public void Turn(){Console.WriteLine("福特开始转弯了");}public void Stop(){Console.WriteLine("福特开始停车了");}}/// <summary>/// 本田车/// </summary>public class HondaCar{public void Run(){Console.WriteLine("本田开始启动了");}public void Turn(){Console.WriteLine("本田开始转弯了");}public void Stop(){Console.WriteLine("本田开始停车了");}}/// <summary>/// 自动驾驶/// </summary>public class AutoSystem{private HondaCar hcar = new HondaCar();private FordCar fcar = new FordCar();private CarType type;public AutoSystem(CarType type){this.type = type;}/// <summary>/// 启动/// </summary>public void RunCar(){if (type == CarType.Ford){fcar.Run();}else{hcar.Run();}}/// <summary>/// 转弯/// </summary>public void TurnCar(){if (type == CarType.Ford){fcar.Turn();}else{hcar.Turn();}}/// <summary>/// 停车/// </summary>public void StopCar(){if (type == CarType.Ford){fcar.Stop();}else{hcar.Stop();}}public enum CarType : int{[Description("福特车")]Ford = 0,[Description("本田车")]Honda = 1,};}{//DIP:依赖倒置原则//福特车AutoSystem fordAutoSystem = new AutoSystem(CarType.Ford);fordAutoSystem.RunCar();fordAutoSystem.TurnCar();fordAutoSystem.StopCar();//本田车AutoSystem hondaAutoSystem = new AutoSystem(CarType.Honda);hondaAutoSystem.RunCar();hondaAutoSystem.TurnCar();hondaAutoSystem.StopCar();}

代码分析:

上面的程序确实能够实现针对Ford和Honda车的无人驾驶,但是在实际的生成场景中需求是不断变化的,比如我们现在又增加了一个新的合作伙伴:宝马车,那我们就需要新定义一个宝马车的实现类,以及对应的枚举CarType和上层的AutoSystem类都需要跟着修改,当随着越来越多的车企加入我们,那我们当前的设计就会变得僵化、脆弱。

如何优化?

导致上面所述问题的一个原因是:含有高层策略的utoSystem模块,依赖于它所控制的低层的具体细节的模块:HondaCar和FordCar。如果我们能够找到一种方法使AutoSystem模块独立于它所控制的具体细节,那么我们就可以自由地复用它了。我们就可以用这个模块来生成其它的程序,使得系统能够用在需要的汽车上。毋庸置疑那就该我们的依赖倒置原则出场了。

优化后的版本(满足依赖倒置原则):

/// <summary>/// 接口层/// </summary>public interface ICar{void Run();void Turn();void Stop();}/// <summary>/// 福特车/// </summary>public class FordCarDIP : ICar{public void Run(){Console.WriteLine("福特开始启动了");}public void Turn(){Console.WriteLine("福特开始转弯了");}public void Stop(){Console.WriteLine("福特开始停车了");}}/// <summary>/// 本田车/// </summary>public class HondaCarDIP : ICar{public void Run(){Console.WriteLine("本田开始启动了");}public void Turn(){Console.WriteLine("本田开始转弯了");}public void Stop(){Console.WriteLine("本田开始停车了");}}/// <summary>/// 自动驾驶/// </summary>public class AutoSystemDIP{private ICar icar;public AutoSystemDIP(ICar icar){this.icar = icar;}/// <summary>/// 启动/// </summary>public void RunCar(){icar.Run();}/// <summary>/// 拐弯/// </summary>public void TurnCar(){icar.Turn();}/// <summary>/// 停车/// </summary>public void StopCar(){icar.Stop();}}{//DIP:依赖倒置原则//福特车ICar car = new FordCarDIP();AutoSystemDIP fordAutoSystem = new AutoSystemDIP(car);fordAutoSystem.RunCar();fordAutoSystem.TurnCar();fordAutoSystem.StopCar();//本田车car = new HondaCarDIP();AutoSystemDIP hondaAutoSystem = new AutoSystemDIP(car);hondaAutoSystem.RunCar();hondaAutoSystem.TurnCar();hondaAutoSystem.StopCar();}

代码分析:

AutoSystem系统依赖于ICar 这个抽象,而与具体的实现细节HondaCar、FordCar无关,所以实现细节的变化不会影响AutoSystem。对于实现细节只要实现ICar 即可,即实现细节依赖于ICar 抽象。

3.优缺点

优点:

  1. 降低类与类之间的耦合性;

  2. 增强系统的稳定性;

  3. 提高代码的可读性和维护性;

  4. 降低修改代码带来的风险;

缺点:

除了抽象难度大点、需要对功能业务理解透彻以外,几乎无缺点,依赖倒置还是我们开发中使用比较频繁的一个原则。

相关文章:

  • GCPS—20型工程钻机的设计自动摊铺机的设计机械设计
  • 影刀RPA_boss直聘翻页(避坑)
  • Redis面试题:Redis的数据过期策略有哪些?
  • 4.一维数组——用数组处理求Fibonacci数列前20项
  • 软件测试面试题之如何进行项目介绍
  • [HCIE] IPSec-VPN (手工模式)
  • 【Docker 系列】不用宝塔面板,小白一样可以玩转docker!
  • 更改MacBook壁纸,有时可以带来不一样的感觉,特别是动态壁纸
  • 一个基于.NET Core开源、跨平台的仓储管理系统
  • 【华为OD题库-037】跳房子2-java
  • cdb数据库强起流程
  • 【传智杯】子串、志愿者、面试题解
  • C 文件 rewind() 函数
  • C语言——深入理解指针(2)
  • STM32 CAN通信自定义数据包多帧连发乱序问题
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • conda常用的命令
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • Java编程基础24——递归练习
  • learning koa2.x
  • mysql 5.6 原生Online DDL解析
  • React的组件模式
  • Spring Cloud中负载均衡器概览
  • vue中实现单选
  • windows下mongoDB的环境配置
  • 观察者模式实现非直接耦合
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 浅谈web中前端模板引擎的使用
  • 如何学习JavaEE,项目又该如何做?
  • 首页查询功能的一次实现过程
  • 双管齐下,VMware的容器新战略
  • 算法之不定期更新(一)(2018-04-12)
  • 微信小程序设置上一页数据
  • 译有关态射的一切
  • ​ArcGIS Pro 如何批量删除字段
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ![CDATA[ ]] 是什么东东
  • #{} 和 ${}区别
  • #13 yum、编译安装与sed命令的使用
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (39)STM32——FLASH闪存
  • (4) PIVOT 和 UPIVOT 的使用
  • (function(){})()的分步解析
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (zt)最盛行的警世狂言(爆笑)
  • (备忘)Java Map 遍历
  • (转)shell中括号的特殊用法 linux if多条件判断
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .NET HttpWebRequest、WebClient、HttpClient
  • .Net Web窗口页属性
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .net 微服务 服务保护 自动重试 Polly
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调