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

设计模式—依赖倒置原则(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. 降低修改代码带来的风险;

缺点:

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


http://www.kler.cn/news/149018.html

相关文章:

  • Android frameworks 开发总结之十一
  • 郑州数字孪生技术推进制造业升级,工业物联网可视化应用加速
  • YOLO改进系列之SKNet注意力机制
  • GitHub 2023排名前十的最佳开源项目
  • 微信小程序+中草药分类+爬虫+torch
  • Linux命令(136)之zcat
  • 芯知识 | 混音播报语音芯片的优势:革新音频应用的新力量
  • 使用 Mybatis 的 TypeHandler 存取 Postgresql jsonb 类型
  • 【数学】旋转矩阵
  • xv6 磁盘中断流程和启动时调度流程
  • Java中实现精度准确的浮点数运算
  • SpringBoot——模板引擎及原理
  • RK3568平台开发系列讲解(Linux系统篇)通过OF函数获取设备树中断信息实验
  • 2023年国赛试题:配置inux1 为 CA 服务器
  • Linux dd命令详解:如何从标准输入或文件中读取、转换并输出数据(附实例教程和注意事项)
  • 7.5 Windows驱动开发:监控Register注册表回调
  • Day09
  • using meta-SQL 使用元SQL
  • awk,sed都可以用号表示查找结果,给查找结果加括号反引号
  • 『 Linux 』进程优先级
  • Pytorch:view()、permute()和contiguous()
  • Unity学习笔记11
  • 【Android Jetpack】Navigation的使用
  • 智能优化算法应用:基于花授粉算法无线传感器网络(WSN)覆盖优化 - 附代码
  • 《尚品甄选》:后台系统——权限管理之分类和品牌管理,使用EasyExcel导入导出数据(debug一遍)
  • 记录vscode常用插件集合(extensions)
  • yml转properties工具
  • 【深度学习】参数优化和训练技巧
  • 森林无人机高效解决巡查难题,林区防火掀新篇
  • 链路追踪详解(二):链路追踪技术的演进