加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

依赖倒转原则

发布时间:2020-12-14 05:16:42 所属栏目:百科 来源:网络整理
导读:【概念】 抽象不应该依赖于细节,细节应该依赖于抽象。 A.????? 高层模块不应该依赖低层模块。两个都应该依赖抽象。 B.????? 抽象不应该依赖于细节,细节应该依赖于抽象。 【解释】 (百度百科解释)就是要依赖于抽象,不要依赖于具体。简单的说就是要求 对

【概念】

抽象不应该依赖于细节,细节应该依赖于抽象。

A.????? 高层模块不应该依赖低层模块。两个都应该依赖抽象。

B.????? 抽象不应该依赖于细节,细节应该依赖于抽象。

【解释】

(百度百科解释)就是要依赖于抽象,不要依赖于具体。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

面向过程的程序设计过程中,上层调用下层,上层依赖于下层,当下层需求发生更改的时候上层的代码就必须要做相应的变动。面向对象的程序设计则考虑:在一般性的情况下,抽象变化的可能性比较小,让客户端依赖于抽象,然而实现的细节也依赖于抽象,只要抽象不变动,那么客户端的程序也就不需要做任何的变动。也就是要针对抽象编程,而不是针对细节编程。

【实例】(百度百科)

某公司是福特和本田公司的金牌合作伙伴,现要求开发一套自动驾驶系统,只要汽车上安装该系统就可以实现无人驾驶,该系统可以在福特和本田车上使用,只要这两个品牌的汽车使用该系统就能实现自动驾驶。

根据所给的需求,模拟这一过程。分析该系统发现可以设计两个基础类“福特车”和“本田车”。然后设计一个自动驾驶类来调用这两个基础类。UML类结构图可以绘制如下:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace denpendrevese
{
    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;
        }

        public void RunCar()
        {
            if(type == CarType.Ford)
            {
                fcar.Run();
            }
            else
            {
                hcar.Run();
            }
        }

        public void TurnCar()
        {
            if(type == CarType.Ford)
            {
                fcar.Turn();
            }
            else
            {
                hcar.Turn();
            }
        }

        public void StopCar()
        {
            if(type == CarType.Ford)
            {
                fcar.Stop();
            }
            else
            {
                hcar.Stop();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            AutoSystem dr = new AutoSystem(AutoSystem.CarType.Honda);
            dr.RunCar();
        }
    }
}

? ? ? ?假设现在需求发生更改,公司的业务发展变大,加入新的汽车品牌“丰田Toyota”。这时候就需要添加“丰田车”相对应的类了。但是问题也就来了:在加入类之后,还要在AutoSystem类中添加相应的代码。加入一个类倒也不费事,但是如果是加入多个类的话,程序的结构就变得十分的复杂了。显然这是和依赖倒转原则相违背的。在上述代码的编写过程中,我们一直是在针对细节(各种的汽车类)进行编程,而不是正对抽象进行编程的。上层模块(AutoSystem)在下层模块(添加Toyota汽车类)发生变动的时候,就要做相应的修改。这对代码的维护产生很大的负面影响。

? ? ? ?现在按照依赖倒转原则重新分析上述问题,如果去掉上层代码和下层代码之间的依赖,也就是为其设计相应的接口,画出UML图如下:


? ? ? ?那么,现在添加Toyota类的时候就不用再去修改上层的AutoSystem类,因为AutoSystem类不依赖于具体的汽车类(细节),AutoSystem类依赖的是ICar这一接口(抽象)。

按照上述分析编写代码,得到:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace denpendrevese
{
    public interface ICar
    {
        void Run();
        void Turn();
        void Stop();
    }
    
    public?class?HondaCar : 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 ToyotaCar : 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;
        }


        public void RunCar()
        {
            icar.Run();
        }

        public void TurnCar()
        {
            icar.Turn();
        }

        public void StopCar()
        {
            icar.Stop();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            AutoSystem dr = new AutoSystem(new ToyotaCar());
            dr.RunCar();
            dr.TurnCar();
            dr.StopCar();
            Console.ReadKey();
        }
    }
}

? ? ? 上述代码中,在添加具体的汽车类后,仅需要添加添加汽车类,并且在客户端代码对其进行实例化就可以了,并不用去修改其他的内容。究其根本就在于,在两个具体的事物中间,我们并不是去关心他们的联系,而是去设计一个他们之间相互调用的接口,就像电脑主板上的内存接口一样。如果我们是电脑组装人员,我们不去管内存条到底是怎么设计实现的(不关注细节),我们只关心他们的接口是不是兼容,如果兼容,那就直接使用就好了。

【总结】

? ? ? 一言以蔽之:要针对抽象编程,而不是针对细节编程。高层的模块通过接口来调用低层的模块,而不是直接对其进行调用。依赖倒转原则的UML图可表示如下:

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读