`
zwt2001267
  • 浏览: 435210 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

(DIP)依赖倒置原则(转)

阅读更多

概述:     

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

意图:

      面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变动时上层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。

      面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度大大的降低了。

面向过程思想的结构图:

截图00

图一

背景1:公司是福特和本田公司的金牌合作伙伴,现要求开发一套自动驾驶系统,只要汽车上安装该系统就可以实现无人驾驶,该系统可以在福特和本田车上使用,只要这两个品牌的汽车使用该系统就能实现自动驾驶。于是有人做出了分析如图一。

对于图一分析:我们定义了一个AutoSystem类,一个FordCar类,一个HondaCar类。FordCar类和HondaCar类中各有三个方法:Run(启动Car)、Turn(转弯Car)、Stop(停止Car),当然了一个汽车肯定不止这些功能,这里只要能说明问题即可。AutoSystem类是一个自动驾驶系统,自动操纵这两辆车。

代码实现:

    public class HondaCar
    {
        public void Run()
        {
            Console.WriteLine("本田开始启动了");
        }
        public void Turn()
        {
            Console.WriteLine("本田开始转弯了");
        }
        public void Stop()
        {
            Console.WriteLine("本田开始停车了");
        }
    }
    public class FordCar
    {
        public void Run()
        {
            Console.WriteLine("福特开始启动了");
        }
        public void Turn()
        {
            Console.WriteLine("福特开始转弯了");
        }
        public void Stop()
        {
            Console.WriteLine("福特开始停车了");
        }
    }
    public class AutoSystem
    {
        public enum CarType { Ford, Honda };
        private HondaCar hcar = new HondaCar();
        private FordCar fcar = new FordCar();
        private CarType type; 
        public AutoSystem(CarType type) { this.type = type; } 
        private void RunCar()
        {
            if (type == CarType.Ford)
            {
                fcar.Run();
            }
            else
            {
                hcar.Run();
            }
        }
        private void TurnCar()
        {
            if (type == CarType.Ford)
            {
                fcar.Turn();
            }
            else
            {
                hcar.Turn();
            }
        }
        private void StopCar()
        {
            if (type == CarType.Ford)
            {
                fcar.Stop();
            }
            else
            {
                hcar.Stop();
            }
        }
    }

代码分析:上面的程序确实能够实现针对Ford和Honda车的无人驾驶,但是软件是在不断变化的,软件的需求也在不断的变化。

背景2:公司的业务做大了,同时成为了通用、三菱、大众的金牌合作伙伴,于是公司要求该自动驾驶系统也能够安装在这3种公司生产的汽车上。于是我们不得不变动AutoSystem:

   public class AutoSystem
    {
        public enum CarType { Ford, Honda ,Bmw};
        HondaCar hcar = new HondaCar();
        FordCar fcar = new FordCar();
        BmwCar bcar = new BmwCar();
        private CarType type;
        public AutoSystem(CarType type)
        {
            this.type = type;
        }
        private void RunCar()
        {
            if (type == CarType.Ford)
            {
                fcar.Run();
            }
            else if (type == CarType.Honda)
            {
                hcar.Run();
            }
            else if (type == CarType.Bmw)
            {
                bcar.Run();
            }
        }
        private void TurnCar()
        {
            if (type == CarType.Ford)
            {
                fcar.Turn();
            }
            else if (type == CarType.Honda)
            {
                hcar.Turn();
            }
            else if (type == CarType.Bmw)
            {
                bcar.Turn();
            }
        }
        private void StopCar()
        {
            if (type == CarType.Ford)
            {
                fcar.Stop();
            }
            else if (type == CarType.Honda)
            {
                hcar.Stop();
            }
            else if (type == CarType.Bmw)
            {
                bcar.Stop();
            }
        }
    }

分析:这会给系统增加新的相互依赖。随着时间的推移,越来越多的车种必须加入到AutoSystem中,这个“AutoSystem”模块将会被if/else语句弄得很乱,而且依赖于很多的低层模块,只要低层模块发生变动,AutoSystem就必须跟着变动,

它最终将变得僵化、脆弱。

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

结构图:

截图00

图二

看图 2中这个简单的类图。这儿有一个“AutoSystem”类,它包含一个“ICar”接口。这个“AutoSystem”类根本不依赖于“FordCar”和“HondaCar”。所以,依赖关系被“倒置”了:“AutoSystem”模块依赖于抽象,那些具体的汽车操作也依赖于相同的抽象。

于是可以添加ICar

    public interface ICar
    {
        void Run();
        void Turn();
        void Stop();
    }
    public class BmwCar:ICar 
    {
        public void Run()
        {
            Console.WriteLine("宝马开始启动了");
        }
        public void Turn()
        {
            Console.WriteLine("宝马开始转弯了");
        }
        public void Stop()
        {
            Console.WriteLine("宝马开始停车了");
        }
    }
    public class FordCar:ICar
    {
        public void Run()
        {
            Console.WriteLine("福特开始启动了");
        }
        public void Turn()
        {
            Console.WriteLine("福特开始转弯了");
        }
        public void Stop()
        {
            Console.WriteLine("福特开始停车了");
        }
    }
    public class HondaCar:ICar
    {
        public void Run()
        {
            Console.WriteLine("本田开始启动了");
        }
        public void Turn()
        {
            Console.WriteLine("本田开始转弯了");
        }
        public void Stop()
        {
            Console.WriteLine("本田开始停车了");
        }
    }
    public class AutoSystem
    {
        private ICar icar;
        public AutoSystem(ICar icar)
        {
            this.icar = icar;
        }
        private void RunCar()
        {
            icar.Run();
        }
        private void TurnCar()
        {
            icar.Turn();
        }
        private void StopCar()
        {
            icar.Stop();
        }
    }

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

综上:

一个应用中的重要策略决定及业务模型正是在这些高层的模块中。也正是这些模型包含着应用的特性。但是,当这些模块依赖于低层模块时,低层模块的修改将会直接影响到它们,迫使它们也去改变。这种境况是荒谬的。应该是处于高层的模块去迫使那些低层的模块发生改变。应该是处于高层的模块优先于低层的模块。无论如何高层的模块也不应依赖于低层的模块。而且,我们想能够复用的是高层的模块。通过子程序库的形式,我们已经可以很好地复用低层的模块了。当高层的模块依赖于低层的模块时,这些高层模块就很难在不同的环境中复用。但是,当那些高层模块独立于低层模块时,它们就能很简单地被复用了。这正是位于框架设计的最核心之处的原则。

总结:依赖倒置原则

A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。

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

分享到:
评论

相关推荐

    OO设计原则 -- OO设计的 DIP依赖倒置原则

    依赖倒置原则的2个重要方针 1.高层模块不应该依赖于低层模块,二者都应该依赖于抽象 2.抽象不应该依赖于细节,细节应该依赖于抽象

    面向对象设计原则-依赖倒置原则示例源码

    依赖倒置原则(Dependence Inversion Principle),缩写为DIP。原始定义:High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend ...

    PHP面向对象五大原则之依赖倒置原则(DIP)详解

    主要介绍了PHP面向对象五大原则之依赖倒置原则(DIP),简单讲述了依赖倒置原则的概念、原理并结合实例形式分析了php依赖倒置原则相关定义与使用方法,需要的朋友可以参考下

    深入理解JavaScript系列(22):S.O.L.I.D五大原则之依赖倒置原则DIP详解

    本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第5篇,依赖倒置原则LSP(The Dependency Inversion Principle )。 英文原文:...

    依赖倒转原则

    依赖倒置原则(Dependence Inversion Principle,简称DIP)这个名字看着有点别扭,“依赖”还“倒置”,这到底是什么意思?依赖倒置原则的原始定义是:High level modules should not depend upon low level modules...

    geocoder-kata:引入依赖倒置原则的代码库

    代码库解释依赖倒置原则 本练习的目标是开发依赖倒置原则 (DIP)。 您的任务:用 OpenStreetMapGeocoding 替换 GoogleGeocoding,并通过这样做来识别和纠正 DIP 违规。

    面向对象设计原则(SRP,OCP,LSP,DIP,ISP)

    面向对象 设计原则 单一职责原则--SRP 开放封闭原则--OCP Liskov替换原则--LSP 依赖倒置原则--DIP 接口隔离原则--ISP

    .NET IoC模式依赖反转(DIP)、控制反转(Ioc)、依赖注入(DI)

    依赖倒置原则(DIP) 依赖倒置(Dependency Inversion Principle,缩写DIP)是面向对象六大基本原则之一。他是指一种特定的的解耦形式,使得高层次的模块不依赖低层次的模块的实现细节,依赖关系被颠倒(反转),从而使得低...

    敏捷软件开发

    DIP 依赖倒置原则 抽象不应该依赖于细节。细节应该依赖于抽象。 ISP 接口隔离原则 不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它 所在的类层次结构。 REP 重用发布等价原则 重用的粒度就是发布的粒度...

    Java_面向对象设计原则总结

    1 依赖倒置原则-Dependency Inversion Principle (DIP) 2 里氏替换原则-Liskov Substitution Principle (LSP) 3 接口分隔原则-Interface Segregation Principle (ISP) 4 单一职责原则-Single ...

    干净的架构React

    依赖倒置原则(DIP) 不要重复自己(干) 你不需要它(YAGNI) 保持简单,愚蠢(KISS) 继承而不是继承 小承诺 设计模式 工厂 适配器 合成的 装饰器 依赖注入 抽象服务器 组成根 方法论设计 TDD 清洁建筑 DDD ...

    OO设计根本的指导原则

    单一职责原则——SRP 开放封闭原则——OCP Liskov替换原则 —— LSP 依赖倒置原则—— DIP 接口隔离原则—— ISP

    SunshlnW#Design-Mode#面向对象设计原则1

    面向对象设计原则常见原则依赖倒置原则(DIP)高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)。封装变化点使用封装来创建对象之间的分界

    设计模式总结

    依赖倒置原则(Dependece Inversion Principle,DIP) 面向接口编程。细节应该依赖抽象。 依赖可以传递。 依赖有三种方式进行传递: 1. 构造函数传递依赖对象 2. setter方法传递依赖对象 3. 接口注入依赖对象 ...

    面向对象设计原则(整理)

    单一职责原则(SRP)、开放-封闭原则(OCP)、Liskov替换原则(LSP)、依赖倒置原则(DIP)、接口分离原则(ISP)

    敏捷软件开发:原则、模式与实践.pdf

    第十一章 依赖倒置原则(DIP) 11.1 依赖倒置原则(DIP) 11.2 层次化 11.3 一个简单的例子 11.4 熔炉示例 11.5 结论 参考文献 第十二章 接口隔离原则(ISP) 12.1 接口污染 12.2 分离客户就是分离接口 12.3 接口...

    深入理解DIP、IoC、DI以及IoC容器

    其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC、DI以及Ioc容器等概念。通过本文我们将一起学习这些概念,并理清他们之间微妙的关系。对于大部分小菜来说,当听到大牛们高谈DIP、IoC、DI以及...

Global site tag (gtag.js) - Google Analytics