• 依赖倒置原则


    概述

    上层模块不应该依赖于下层模块,二者都应该依赖于抽象。

    抽象不应该有具体的实现,但是具体的实现应当依赖于抽象。

    描述

    在系统架构分析和设计中,软件的创建总是会带有一些错误的依赖关系,比如说业务逻辑依赖于底层实现,这种情形往往会导致业务逻辑变更,下层实现随之改变。当然,反过来也是成立的。因此,我们需要将彼此的依赖关系进行反转,这也是依赖倒置原则被引入的原因。

    下面我们以按钮和灯的关系来进行讲解。

    一般情况下,我们会这样的组织二者之间的关系:

    using System;
    
    namespace DependencyInversionDaemon
    {
        class Light
        {
            public void TurnOn()
            {
                Console.WriteLine("The light is on.");
            }
    
            public void TurnOff()
            {
                Console.WriteLine("The light is off.");
            }
        }
    }
    Light.cs代码
    namespace DependencyInversionDaemon
    {
        class ButtonEx
        {
            private Light light = new Light();
            private bool pressed = false;
    
            public void Press()
            {
                if (pressed)
                    light.TurnOn();
                else
                    light.TurnOff();
                pressed = !pressed;
            }
        }
    }
    ButtonEx.cs代码

    Light类被ButtonEx类控制,这是典型的耦合度过高的设计。控制的逻辑部分在ButtonEx中,而下层的扩展则在Light类中,所以,ButtonEx类属于上层扩展部分而Light类则属于下层扩展部分。

    所以,依赖方向是从ButtonEx类流向了Light类。如果Light类需要进行扩展,那么ButtonEx类将会受到影响。这就意味着,下层需求部分的改变将会影响上层应用部分。

    重构

    理想情况下,业务逻辑将会决定下层代码如何扩展,所以,下层模块应该依赖于业务逻辑。

    但是,通过依赖倒置原则,我们应该讲ButtonEx类和Light类进行解耦,解耦的方式就是引入一个虚类,这个虚类能够将Light类中的具体行为抽象出来。

    现在,我们在类中新加入一个Switchable类,这个类包含了ButtonEx类所需要的各种操作(也就是上层扩展中所需要的各种操作功能,比如TurnOn,TurnOff等)。ButtonEx类和Light类将不会直接的进行调用,而是通过这个Switchable中间类实现依赖倒置。

    namespace DependencyInversionDaemons
    {
        interface Switchable
        {
            void TurnOn();
            void TurnOff();
        }
    }
    Switchable.cs代码
    using System;
    
    namespace DependencyInversionDaemons
    {
        class Light:Switchable
        {
            public void TurnOn()
            {
                Console.WriteLine("The light is on.");
            }
    
            public void TurnOff()
            {
                Console.WriteLine("The light is off.");
            }
    
        }
    }
    Light.cs代码
    using System;
    
    namespace DependencyInversionDaemons
    {
        class Fridge:Switchable
        {
            public void TurnOn()
            {
                Console.WriteLine("The fridge is on.");
            }
    
            public void TurnOff()
            {
                Console.WriteLine("The fridge is off.");
            }
        }
    }
    Fridge.cs代码
    namespace DependencyInversionDaemons
    {
        class ButtonEx
        {
            private Switchable swithableObjects;
            private bool pressed = false;
    
            public void SetSwitchable(Switchable switchable)
            {
                this.swithableObjects = switchable;
            }
    
            public void Press()
            {
                if (pressed)
                    swithableObjects.TurnOn();
                else
                    swithableObjects.TurnOff();
                pressed = !pressed;
            }
        }
    }
    ButtonEx.cs代码
    using System;
    
    namespace DependencyInversionDaemons
    {
        class Program
        {
            static void Main(string[] args)
            {
                ButtonEx button = new ButtonEx();
                button.SetSwitchable(new Fridge());
                button.Press();
                button.Press();
                Console.ReadKey(); 
            }
        }
    }
    调用代码

    现在,当我们向这个工程里添加其他的设备的时候,就不需要改变ButtonEx类中的任何代码,这种依赖关系已经被解耦了。这种设计符合面向对象原则:松耦合,高内聚。

    最后需要补充一点就是,依赖倒置原则,其实需要我们不要为实现而编程,要为接口编程。

  • 相关阅读:
    艾伟:WCF从理论到实践(17):OO大背离(带视频+ppt+源码) 狼人:
    艾伟:MOSS 2007 项目的开发步骤 狼人:
    艾伟:WM有约(一):你好,CF 狼人:
    艾伟:WCF从理论到实践(13):事务投票 狼人:
    艾伟:WCF从理论到实践(15):响应变化 狼人:
    艾伟:Remember: 我们是做产品的,不是搞学术研究的 & 用事实说话,不要臆断 狼人:
    艾伟:WCF从理论到实践(10):异常处理 狼人:
    艾伟:WCF从理论到实践(16):操作重载(带视频+ppt+源码) 狼人:
    艾伟:WCF从理论到实践(12):事务 狼人:
    艾伟:[WCF的Binding模型]之五:绑定元素(Binding Element) 狼人:
  • 原文地址:https://www.cnblogs.com/scy251147/p/3268519.html
Copyright © 2020-2023  润新知