1. 程式人生 > >C#軟體設計——小話設計模式原則之:依賴倒置原則DIP

C#軟體設計——小話設計模式原則之:依賴倒置原則DIP

前言:很久之前就想動筆總結下關於軟體設計的一些原則,或者說是設計模式的一些原則,奈何被各種bootstrap元件所吸引,一直抽不開身。群裡面有朋友問博主是否改行做前端了,呵呵,其實博主是想做“全戰”,即各方便都有戰鬥力。關於設計模式,作為程式猿的我們肯定都不陌生。博主的理解,所謂設計模式就是前人總結下來的一些對於某些特定使用場景非常適用的優秀的設計思路,“前人栽樹,後人乘涼”,作為後來者的我們就有福了,當我們遇到類似的應用場景的時候就可以直接使用了。關於設計模式的原則,博主將會在接下來的幾篇裡面根據自己的理解一一介紹,此篇就先來看看設計模式的設計原則之——依賴倒置原則。

軟體設計原則系列文章索引

一、原理介紹

1、官方定義

依賴倒置原則,英文縮寫DIP,全稱Dependence Inversion Principle。

原始定義:High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions。

官方翻譯:高層模組不應該依賴低層模組,兩者都應該依賴其抽象;抽象不應該依賴細節,細節應該依賴抽象。

2、自己理解

2.1、原理解釋

上面的定義不難理解,主要包含兩次意思:

1)高層模組不應該直接依賴於底層模組的具體實現,而應該依賴於底層的抽象。換言之,模組間的依賴是通過抽象發生,實現類之間不發生直接的依賴關係,其依賴關係是通過介面或抽象類產生的。

2)介面和抽象類不應該依賴於實現類,而實現類依賴介面或抽象類。這一點其實不用多說,很好理解,“面向介面程式設計”思想正是這點的最好體現。

2.2、被“倒置”的依賴

相比傳統的軟體設計架構,比如我們常說的經典的三層架構,UI層依賴於BLL層,BLL層依賴於DAL層。由於每一層都是依賴於下層的實現,這樣當某一層的結構發生變化時,它的上層就不得不也要發生改變,比如我們DAL裡面邏輯發生了變化,可能會導致BLL和UI層都隨之發生變化,這種架構是非常荒謬的!好,這個時候如果我們換一種設計思路,高層模組不直接依賴低層的實現,而是依賴於低層模組的抽象

,具體表現為我們增加一個IBLL層,裡面定義業務邏輯的介面,UI層依賴於IBLL層,BLL層實現IBLL裡面的介面,所以具體的業務邏輯則定義在BLL裡面,這個時候如果我們BLL裡面的邏輯發生變化,只要介面的行為不變,上層UI裡面就不用發生任何變化。

在經典的三層裡面,高層模組直接依賴低層模組的實現,當我們將高層模組依賴於底層模組的抽象時,就好像依賴“倒置”了。這就是依賴倒置的由來。通過依賴倒置,可以使得架構更加穩定、更加靈活、更好應對需求變化。

2.3、依賴倒置的目的

上面說了,在三層架構裡面增加一個介面層能實現依賴倒置,它的目的就是降低層與層之間的耦合,使得設計更加靈活。從這點上來說,依賴倒置原則也是“鬆耦合”設計的很好體現。

二、場景示例

 文章最開始的時候說了,依賴倒置是設計模式的設計原則之一,那麼在我們那麼多的設計模式中,哪些設計模式遵循了依賴倒置的原則呢?這個就多了,比如我們常見的工廠方法模式。下面博主就結合一個使用場景來說說依賴倒置原則如何能夠使得設計更加靈活。

場景描述:還記得在C#基礎系列——一場風花雪月的邂逅:介面和抽象類這篇裡面介紹過裝置的採集的例子,這篇繼續以這個使用場景來說明。裝置有很多型別,每種裝置都有登入和採集兩個方法,通過DeviceService這個服務去啟動裝置的採集,最開始我們只有MML和TL2這兩種型別的裝置,那麼來看看我們的設計程式碼。

程式碼示例:

  //MML型別的裝置
    public class DeviceMML
    {
        public void Login()
        {
            Console.WriteLine("MML裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("MML裝置採集");
            return true;
        }
    }

    //TL2型別裝置
    public class DeviceTL2
    {
        public void Login()
        {
            Console.WriteLine("TL2裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("TL2裝置採集");
            return true;
        }
    }

    //裝置採集的服務
    public class DeviceService
    {
        private DeviceMML MML = null;
        private DeviceTL2 TL2 = null;
        private string m_type = null;
        //建構函式裡面通過型別來判斷是哪種型別的裝置
        public DeviceService(string type)
        {
            m_type = type;
            if (type == "0")
            {
                MML = new DeviceMML();
            }
            else if (type == "1")
            {
                TL2 = new DeviceTL2();
            }
        }

        public void LoginDevice()
        {
            if (m_type == "0")
            {
                MML.Login();
            }
            else if (m_type == "1")
            {
                TL2.Login();
            }
        }

        public bool DeviceSpider()
        {
            if (m_type == "0")
            {
                return MML.Spider();
            }
            else if (m_type == "1")
            {
                return TL2.Spider();
            }
            else
            {
                return true;
            }
        }
    }

在Main函式裡面呼叫

   class Program
    {

        static void Main(string[] args)
        {
            var oSpider = new DeviceService("1");
            oSpider.LoginDevice();
            var bRes = oSpider.DeviceSpider();
            
            Console.ReadKey();
        }

上述程式碼經過開發、除錯、部署、上線。可以正常執行,貌似一切都OK。

日復一日、年復一年。後來公司又來兩種新的裝置TELNET和TL5型別裝置。於是程式猿們又有得忙了,加班,趕進度!於是程式碼變成了這樣:

   //MML型別的裝置
    public class DeviceMML
    {
        public void Login()
        {
            Console.WriteLine("MML裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("MML裝置採集");
            return true;
        }
    }

    //TL2型別裝置
    public class DeviceTL2
    {
        public void Login()
        {
            Console.WriteLine("TL2裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("TL2裝置採集");
            return true;
        }
    }

    //TELNET型別裝置
    public class DeviceTELNET
    {
        public void Login()
        {
            Console.WriteLine("TELNET裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("TELNET裝置採集");
            return true;
        }
    }

    //TL5型別裝置
    public class DeviceTL5
    {
        public void Login()
        {
            Console.WriteLine("TL5裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("TL5裝置採集");
            return true;
        }
    }


    //裝置採集的服務
    public class DeviceService
    {
        private DeviceMML MML = null;
        private DeviceTL2 TL2 = null;
        private DeviceTELNET TELNET = null;
        private DeviceTL5 TL5 = null;
        private string m_type = null;
        //建構函式裡面通過型別來判斷是哪種型別的裝置
        public DeviceService(string type)
        {
            m_type = type;
            if (type == "0")
            {
                MML = new DeviceMML();
            }
            else if (type == "1")
            {
                TL2 = new DeviceTL2();
            }
            else if (type == "2")
            {
                TELNET = new DeviceTELNET();
            }
            else if (type == "3")
            {
                TL5 = new DeviceTL5();
            }
        }

        public void LoginDevice()
        {
            if (m_type == "0")
            {
                MML.Login();
            }
            else if (m_type == "1")
            {
                TL2.Login();
            }
            else if (m_type == "2")
            {
                TELNET.Login();
            }
            else if (m_type == "3")
            {
                TL5.Login();
            }
        }

        public bool DeviceSpider()
        {
            if (m_type == "0")
            {
                return MML.Spider();
            }
            else if (m_type == "1")
            {
                return TL2.Spider();
            }
            else if (m_type == "2")
            {
                return TELNET.Spider();
            }
            else if (m_type == "3")
            {
                return TL5.Spider();
            }
            else
            {
                return true;
            }
        }
    }

比如我們想啟動TL5型別裝置的採集,這樣呼叫可以實現:

        static void Main(string[] args)
        {
            var oSpider = new DeviceService("3");
            oSpider.LoginDevice();
            var bRes = oSpider.DeviceSpider();
         
            Console.ReadKey();
        }

花了九年二虎之力,總算是可以實現了。可是又過了段時間,又有新的裝置型別呢?是不是又要加班,又要改。這樣下去,感覺這就是一個無底洞,再加上時間越久,專案所經歷的開發人員越容易發生變化,這個時候再改,那維護的成本堪比開發一個新的專案。並且,隨著裝置型別的增多,程式碼裡面充斥著大量的if...else,這樣的爛程式碼簡直讓人無法直視。

基於這種情況,如果我們當初設計這個系統的時候考慮了依賴倒置,那麼效果可能截然不同。我們來看看依賴倒置如何解決以上問題的呢?

    //定義一個統一介面用於依賴
    public interface IDevice
    {
        void Login();
        bool Spider();
    }

    //MML型別的裝置
    public class DeviceMML : IDevice
    {
        public void Login()
        {
            Console.WriteLine("MML裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("MML裝置採集");
            return true;
        }
    }

    //TL2型別裝置
    public class DeviceTL2 : IDevice
    {
        public void Login()
        {
            Console.WriteLine("TL2裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("TL2裝置採集");
            return true;
        }
    }

    //TELNET型別裝置
    public class DeviceTELNET : IDevice
    {
        public void Login()
        {
            Console.WriteLine("TELNET裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("TELNET裝置採集");
            return true;
        }
    }

    //TL5型別裝置
    public class DeviceTL5 : IDevice
    {
        public void Login()
        {
            Console.WriteLine("TL5裝置登入");
        }

        public bool Spider()
        {
            Console.WriteLine("TL5裝置採集");
            return true;
        }
    }


    //裝置採集的服務
    public class DeviceService
    {
        private IDevice m_device;
        public DeviceService(IDevice oDevice)
        {
            m_device = oDevice;
        }

        public void LoginDevice()
        {
            m_device.Login();
        }

        public bool DeviceSpider()
        {
            return m_device.Spider();
        }
    }

呼叫

     static void Main(string[] args)
        {
            var oSpider = new DeviceService(new DeviceTL5());
            oSpider.Login();
            var bRes = oSpider.Spider();

            Console.ReadKey();
        }

程式碼說明:上述解決方案中,我們定義了一個IDevice介面,用於上層服務的依賴,也就是說,上層服務(這裡指DeviceService)僅僅依賴IDevice介面,對於具體的實現類我們是不管的,只要介面的行為不發生變化,增加新的裝置型別後,上層服務不用做任何的修改。這樣設計降低了層與層之間的耦合,能很好地適應需求的變化,大大提高了程式碼的可維護性。呵呵,看著是不是有點眼熟?是不是有點像某個設計模式?其實設計模式的設計原理正是基於此。

三、使用Unity實現依賴倒置

上面說了那麼多,都是在講依賴倒置的好處,那麼在我們的專案中究竟如何具體實現和使用呢?

在介紹依賴倒置具體如何使用之前,我們需要引入IOC容器相關的概念,我們先來看看它們之間的關係。

依賴倒置原則(DIP):一種軟體架構設計的原則(抽象概念)。

控制反轉(IoC):一種反轉流、依賴和介面的方式(DIP的具體實現方式)。這是一個有點不太好理解和解釋的概念,通俗地說,就是應用程式本身不負責依賴物件的建立和維護,而是將它交給一個外部容器(比如Unity)來負責,這樣控制權就由應用程式轉移到了外部IoC 容器,即控制權實現了所謂的反轉。例如在型別A中需要使用型別B的例項,而B 例項的建立並不由A 來負責,而是通過外部容器來建立。

依賴注入(DI):IoC的一種實現方式,用來反轉依賴(IoC的具體實現方式)。園子裡面很多博文裡面說IOC也叫DI,其實根據博主的理解,DI應該是IOC的具體實現方式,比如我們如何實現控制反轉,答案就是通過依賴注入去實現。

IoC容器:依賴注入的框架,用來對映依賴,管理物件建立和生存週期(DI框架),自動建立、維護依賴物件。

這些名詞是不是有點熟呢?博主之前介紹過MEF,之前使用MEF做過依賴注入,詳見C#進階系列——MEF實現設計上的“鬆耦合”(一)。其實嚴格來講,MEF不能算一種正式的IOC容器,因為它的主要作用還是用於應用程式擴充套件,避免生成脆弱的硬依賴項,而不是依賴注入。根據博主的瞭解以及使用經歷,常用的IOC容器有:

當然,還有其他的IOC容器這裡就不一一列舉。Spring.net是從Java的Spring框架移植過來的,功能之強大我們就不多說了,可是自從它宣佈不再更新,博主在使用它的時候就非常慎重了。下面博主還是就Unity這種IOC容器來看看依賴倒置的具體實現。

1、Unity引入

Unity如何引入?我們神奇的Nuget又派上用場了。最新的Unity版本已經到了4.0.1。

安裝成功後主要引入了三個dll。

2、Unity常用API

UnityContainer.RegisterType<ITFrom,TTO>();

UnityContainer.RegisterType< ITFrom, TTO >();

UnityContainer.RegisterType< ITFrom, TTO >("keyName");

IEnumerable<T> databases = UnityContainer.ResolveAll<T>();

IT instance = UnityContainer.Resolve<IT>();

T instance = UnityContainer.Resolve<T>("keyName");

UnitContainer.RegisterInstance<T>("keyName",new T());

UnityContainer.BuildUp(existingInstance);

IUnityContainer childContainer1 = parentContainer.CreateChildContainer();

3、程式碼注入方式示例

3.1、預設註冊方式

仍然以上面的場景為例說明,我們注入DeviceMML這個實現類。

    class Program
    {
        private static IUnityContainer container = null;
        static void Main(string[] args)
        {
            RegisterContainer();
            var oSpider = container.Resolve<IDevice>();
            oSpider.Login();
            var bRes = oSpider.Spider();

            Console.ReadKey();
        }

        /// <summary>
        /// 程式碼注入
        /// </summary>
        public static void RegisterContainer()
        {
            container = new UnityContainer();
            container.RegisterType<IDevice, DeviceMML>();  //預設註冊方式,如果後面再次預設註冊會覆蓋前面的
        }
    }

執行結果

3.2、帶命名方式的註冊

上面預設注入的方式中,我們只能注入一種具體的例項,如果我們需要同時注入多個型別的例項呢?看看我們的 RegisterType() 方法有多個過載。

   class Program
    {
        private static IUnityContainer container = null;
        static void Main(string[] args)
        {
            RegisterContainer();
            var oSpider = container.Resolve<IDevice>("TL5");
            oSpider.Login();
            var bRes = oSpider.Spider();

            Console.ReadKey();
        }

        /// <summary>
        /// 程式碼注入
        /// </summary>
        public static void RegisterContainer()
        {
            container = new UnityContainer();
           container.RegisterType<IDevice, DeviceMML>("MML");  //預設註冊(無命名),如果後面還有預設註冊會覆蓋前面的
            container.RegisterType<IDevice, DeviceTELNET>("Telnet");  //命名註冊
            container.RegisterType<IDevice, DeviceTL2>("TL2");  //命名註冊
            container.RegisterType<IDevice, DeviceTL5>("TL5");  //命名註冊
        }
    }

執行結果

4、配置檔案注入方式示例

在App.config或者Web.config裡面加入如下配置:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity>
    <!--容器-->
    <containers>
      <container name="Spider">
        <!--對映關係-->
        <register type="ESTM.Spider.IDevice,ESTM.Spider"  mapTo="ESTM.Spider.DeviceMML,ESTM.Spider" name="MML"></register>
        <register type="ESTM.Spider.IDevice,ESTM.Spider"  mapTo="ESTM.Spider.DeviceTELNET,ESTM.Spider" name="TELNET"></register>
        <register type="ESTM.Spider.IDevice,ESTM.Spider"  mapTo="ESTM.Spider.DeviceTL2,ESTM.Spider" name="TL2"></register>
        <register type="ESTM.Spider.IDevice,ESTM.Spider"  mapTo="ESTM.Spider.DeviceTL5,ESTM.Spider" name="TL5"></register>
      </container>
    </containers>
  </unity>
</configuration>

在程式碼裡面註冊配置檔案:

namespace ESTM.Spider
{
    class Program
    {
        private static IUnityContainer container = null;
        static void Main(string[] args)
        {
            ContainerConfiguration();
            var oSpider = container.Resolve<IDevice>("TL5");
            oSpider.Login();
            var bRes = oSpider.Spider();

            Console.ReadKey();
        }

        /// <summary>
        /// 配置檔案注入
        /// </summary>
        public static void ContainerConfiguration()
        {
            container = new UnityContainer();
            UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
            configuration.Configure(container, "Spider");
        }

    }
}

執行結果:

程式碼說明

(1)

<register type="ESTM.Spider.IDevice,ESTM.Spider"  mapTo="ESTM.Spider.DeviceMML,ESTM.Spider" name="MML"></register>

節點裡面,type物件抽象,mapTo物件具體例項物件,name物件例項的別名。

(2)在app.config裡面可以配置多個 <container name="Spider"> 節點,不同的name配置不同的依賴物件。

(3)配置檔案注入的靈活之處在於解耦。為什麼這麼說呢?試想,如果我們的IDevice介面對應著一個介面層,而DeviceMML、DeviceTELNET、DeviceTL2、DeviceTL5等實現類在另外一個實現層裡面,我們的UI層(這裡對應控制檯程式這一層)只需要新增IDevice介面層的引用,不必新增實現層的引用,通過配置檔案注入,在執行的時候動態將實現類注入到UI層裡面來。這樣UI層就對實現層實現瞭解耦,實現層裡面的具體邏輯變化時,UI層裡面不必做任何更改。

四、總結

 到此,依賴倒置原則的講解基本結束了。根據博主的理解,設計模式的這些原則是設計模式的理論指導,而設計模式則是這些理論的具體運用。說一千道一萬,要想搞懂設計模式,必須先了解設計模式遵循的原則,無論是哪種設計模式都會遵循一種或者多種原則。當然文章可能有理解不當的地方,歡迎大牛們指出。博主將會在接下來的幾章繼續總結下其他設計原則,如果園友們覺得本文對你有幫助,請幫忙推薦,博主將繼續努力~~

相關推薦

C#軟體設計——設計模式原則依賴倒置原則DIP

前言:很久之前就想動筆總結下關於軟體設計的一些原則,或者說是設計模式的一些原則,奈何被各種bootstrap元件所吸引,一直抽不開身。群裡面有朋友問博主是否改行做前端了,呵呵,其實博主是想做“全戰”,即各方便都有戰鬥力。關於設計模式,作為程式猿的我們肯定都不陌生。博主的理解,所謂設計模式就是前人總結下來的一些

面向對象設計原則依賴倒置原則

設計原則 面向 dip 定性 穩定 要求 這樣的 覆蓋 通過 依賴倒置原則(DIP) 定義:高層模塊不應該依賴底層模塊,兩者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。   好處:穩定性、可維護性、可擴展性。  概述:DI就是依賴倒置的意思,也可稱

C#軟體設計——設計模式原則開閉原則OCP

前言:這篇繼續來看看開閉原則。廢話少說,直接入正題。 軟體設計原則系列文章索引 一、原理介紹 1、官方定義 開閉原則,英文縮寫OCP,全稱Open Closed Principle。 原始定義:Software entities (classes, modules, functions) sho

C#軟體設計——設計模式原則單一職責原則SRP

前言:上篇C#軟體設計——小話設計模式原則之:依賴倒置原則DIP簡單介紹了下依賴倒置的由來以及使用,中間插了兩篇WebApi的文章,這篇還是迴歸正題,繼續來寫寫設計模式另一個重要的原則:單一職責原則。 軟體設計原則系列文章索引 一、原理介紹 1、官方定義 單一職責原則,英文縮寫SRP,全稱Sing

C#軟體設計——設計模式原則介面隔離原則ISP

前言:有朋友問我,設計模式原則這些東西在園子裡都討論爛了,一搜一大把的資料,還花這麼大力氣去整這個幹嘛。博主不得不承認,園子裡確實很多這方面的文章,並且不乏出色的博文。博主的想法是,既然要完善知識體系,就不能半途而廢。今天就來看看設計模式原則的另一個:介面隔離原則。 軟體設計原則系列文章索引 一、原理

設計模式原則單一職責原則SRP(C#篇)

正文 前言:上篇C#軟體設計——小話設計模式原則之:依賴倒置原則DIP簡單介紹了下依賴倒置的由來以及使用,中間插了兩篇WebApi的文章,這篇還是迴歸正題,繼續來寫寫設計模式另一個重要的原則:單一職責原則。 軟體設計原則系列文章索引 回到頂部 一、原理介紹 回到頂部

【學習筆記】慕課網—Java設計模式精講 第3章 軟體設計七大原則-3-3 依賴倒置原則

/** * 軟體設計七大原則-依賴倒置原則 學習筆記 * @author cnRicky * @date 2018.11.10 */ 依賴倒置原則 高層模組不應該依賴低層模組,二者都應該依賴其抽象 抽象不應該依賴細節;細節應該依賴抽象 針對介面程式設計,不要針對實現程式設計(儘

設計模式六大原則(3)依賴倒置原則

定義:高層模組不應該依賴低層模組,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。 問題由來:類A直接依賴類B,假如要將類A改為依賴類C,則必須通過修改類A的程式碼來達成。這種場景下,類A一般是高層模組,負責複雜的業務邏輯;類B和類C是低層模組,負責基本的原子操作

(轉)設計模式六大原則(3)依賴倒置原則

定義:高層模組不應該依賴低層模組,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。 問題由來:類A直接依賴類B,假如要將類A改為依賴類C,則必須通過修改類A的程式碼來達成。這種場景下,類A一般是高層模組,負責複雜的業務邏輯;類B和類C是低層模組,負責基本的原子

設計模式原則依賴倒置原則

1、什麼是依賴倒轉原則?   所謂依賴倒置原則,就是不論高層元件和低層元件都應該依賴於抽象,而不是具體實現類。聽起來更像是“針對介面程式設計,而不是針對實現程式設計”,但是這裡依賴倒置原則更強調“抽象”的概念,不要讓高層元件依賴低層元件,更不能依賴具體實現類,都要依賴於抽象。依賴倒置原則的核心在於“面向介

面向對象設計原則依賴倒置原則

ron 通過 發生 需要 系統 面向對象設計 啟動 模塊 == 依賴倒置原則 所謂依賴倒置原則(Dependence Inversion Principle )就是要依賴於抽象,不要依賴於具體。簡單的說就是對抽象進行編程,不要對實現進行編程,這樣就降低了客戶與實

OO設計原則 -- Dependency Inversion Principle依賴倒置原則(DIP)

依賴倒置原則的2個重要方針 A. High level modules should not depend upon low level modules. Both shoulddepend upon abstractions. 高層模組不應該依賴於低層模組,二

面向物件設計原則--里氏替換原則(LSP)和依賴倒置原則(DIP)

面向物件設計原則–里氏替換原則(LSP)和依賴倒置原則(DIP) tags:設計模式 LSP–inheritance should ensure that any property prove

SOLDI原則DIP依賴倒置原則

本篇介紹軟體設計原則之一DIP:依賴倒置原則。很多知識回頭來看會有新的理解。看到一句話,一段文字,一個觀點有了新的理解,醍醐灌頂的感覺。這種感覺像是一種驚喜。古語說:溫故而知新。 DIP:依賴倒置原則 a.高層模組不應該依賴於低層模組。二者都應該依賴於抽象。 b.抽象不應該依賴於細節。細節應該依

面向物件六大原則(三)依賴倒置原則

出處:http://blog.csdn.net/zhengzhb/article/details/7289269 定義:高層模組不應該依賴低層模組,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。 問題由來:類A直接依賴類B,假如要將類A改為依賴類C,則必須通

設計模式軟體開發原則(1)開閉原則依賴倒置原則

開閉原則 定義 所謂開閉原則就是一個軟體實體如類、模組和函式應該對擴充套件開放、對修改關閉。 強呼叫抽象構建框架,實現實現拓展細節。 有優點是提高軟體的複用性和易維護展性。是面向物件的最基本原則。 依賴倒置原則 定義 高層模組不應該依賴底層模組,二者都應該依賴其抽象。 抽象不應該依賴細節:細節應該

設計模式六大原則裏氏替換原則

number -h ole 擁有 method about rect sse 程序 1 裏氏替換原則定義 Liskov於1987年提出了一個關於繼承的原則“Inheritance should ensure that any property proved about su

設計模式學習筆記(二) 設計基本原則【單一職責原則

code 分享 開發者 實際應用 需要 ret ext file類 tor 單一職責原則(SRP: Single Responsibility Principle) 名詞解釋: 1) 職責:是指類變化的原因。 2) 職責擴散:就是因為某種原因,職責P被分化為粒度更細的職責P

設計模式六大原則(一)單一職責原則

控制 line 避免 多人 由來 pan 兩個類 思想 功能 單一職責定義: 不要存在多於一個導致類變更的原因,通俗的說,即一個類只負責一項職責。 問題由來: 類T負責兩個不同的職責:職責P1,職責P2。當由於職責P1需求發生改變而需要修改類T時,有可能會導致原

[轉]設計模式六大原則[6]開閉原則

說了 一點 模塊 活性 問題 單一職責原則 就是 認識 適應 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行