1. 程式人生 > >C#設計模式前奏-面向物件設計原則

C#設計模式前奏-面向物件設計原則

          在學習設計模式之前,面向物件設計原則是必須要了解的東西。因為大多數設計模式都遵循這些設計原則中的一種或者多種。今天就帶大家一起去學習學習七類面向設計原則。首先列出常用的7中面向物件設計原則。下面的這個表格裡面的內容有些比較抽象,您可能看不懂,但是沒關係,後面我會做詳細解釋,並且有配套的視訊教程。

                                                                      7種常用的面向物件設計原則

設計原則名稱

定義

單一職責原則(SRP)

一個物件應該只包含單一的職責,並且該職責被完全封裝在一個類中

開閉原則(OCP)

軟體實體應當對擴充套件開放,對修改關閉

里氏代換原則(LSP)

所有引用基類的地方必須透明的使用其子類的物件

依賴倒轉原則(DIP)

高層模組不應該依賴低層模組,他們都應該依賴抽象。抽象不應該依賴於細節,細節應該依賴於抽象

介面隔離原則(ISP)

客戶端不應該依賴那些他不需要的介面

合成複用原則(CRP)

優先使用物件組合,而不是繼承來達到複用的目的

迪米特法則(LoD)

每一個軟體單位對其他單位都只有最少的知識,而且侷限於那些與本單位密切相關的軟體單位


一、單一職責原則

        單一職責原則是最簡單的設計原則,它用來控制類的粒度,其實通俗一點說就是控制一個類能承擔多大的職責,再者就是一個類應該只包含某一類職責。比如說最常用的SQLHleper類,它承擔的職責就是封裝和資料庫操作有關的操作。下面舉一個簡單的例子來說。

public class Student
    {
        public SqlConnection GetConnection()//連線資料庫
        {
            string str = "";
            return new SqlConnection(str);
        }
        public string GetStudentName()//查詢學生姓名
        {
            SqlConnection conn = GetConnection();//連線資料庫
            //省略查詢資訊
            return "son";
        }
        public void DelStudent(string studentId )//根據學號刪除學生
        {
            SqlConnection conn = GetConnection();//連線資料庫
            //省略刪除操作
        }

    }


        這段程式碼我相信很多初學者都非常熟悉。這是一個學生類Student類,裡面有三個方法GetSqlconnection(),GetStudentName()和DelStudent(string studentId)。他們的作用分別是連線資料庫,查詢學生姓名,根據學號刪除學生資訊。因為查詢學生資訊和刪除學生要連結資料庫進行操作,所以對於初學者來說,比較習慣把他們寫在一起。但是這個時候我們的寫法就違背了單一職責原則。因為這個類既承擔了和資料庫有關的操作,又承擔了和學生資訊有關的增刪操作.它承擔了兩類職責。而且一般情況下某個類承擔的職責可以直接從類名上體現出來,比如Student類,它的職責就是處理和學生有關的一些操作。

     那我們怎麼做才能讓它符合單一職責原則呢,把不同的職責提取出來放到不同的類中就可以。接下來看下一段程式碼:

    public class Student
    {
        
        public string GetStudentName()//查詢學生姓名
        {
            SqlConnection conn = SQLHelper.GetConnection();//連線資料庫
            //省略查詢資訊
            return "son";
        }
        public void DelStudent(string studentId )//根據學號刪除學生
        {
            SqlConnection conn = SQLHelper.GetConnection();//連線資料庫
            //省略刪除操作
        }
    }
    public class SQLHelper
    {
        public static SqlConnection GetConnection()//連線資料庫
        {
            string str = "";
            return new SqlConnection(str);
        }
    }


     我們把GetConnection()方法單獨拿出來放到SQLHelper類中,在Student類中去呼叫它就OK。這個時候我們的程式碼就符合了單一職責原則啦!

    最後我把兩種寫法的類圖貼出來方便大家理解:


二、開閉原則

        這個原則裡面的開指的是對擴充套件開放,閉指的是對修改關閉。

       通俗一點說就是我們在擴充套件(開)系統的時候儘量不修改(閉)原始碼。這幾乎也是我們開發軟體的終極目標。但實際上在任何一個軟體裡面,這個開閉原則幾乎是不可能百分之百達到。通常我們擴充套件系統的時候,多多少少都會修改原始碼。

      這個原則就不給大家舉例子了,我相信很容易理解的。

     為了滿足開閉原則,我們就要對系統進行抽象化設計,抽象化是開閉原則的關鍵所在。在直接一點說就是我們要針對抽象程式設計,而不是針對實現程式設計。

    開閉原則一直以來都是評判一個軟體靈活性和可擴充套件性的一個重要依據。

三、里氏代換原則

  這個原則的定義是:所有引用基類的地方必須能透明的使用使用子類物件。這句話可能比較抽象,我的理解就是,在程式中使用基類進行定義,在執行時確定其子類型別。

    假如說一個網站上的會員有普通會員,VIP會員,同時VIP的等級也可能有差距。現在我們要實現一個功能,想不同型別的會員發

送不同的系統郵件。

    如果用比較原始的方法,我們可能會這麼實現:

   這個時候我們在郵件傳送類裡面寫了三個方法,分別是給三種不同型別的會員傳送系統郵件,如果這個時候我們要新增一種會員

型別,那就必須要修改郵件傳送類EmailSender,這點其實違背了上面的開閉原則(對修改關閉,而我們修改了EmailSender)。那如何解決這個問題呢,里氏替換原則在這裡就起了作用。這三種會員型別我們可以給他抽象出一個父類Member,SendEmail類直接針對Member程式設計就可以。因為Member可以替換子類(Member m=new CommonMember)。大家先看下面的類圖:


         如果這個時候再增加會員型別,那隻需要再增加一個類(假設這個類是VIP3Member)讓他繼承Member即可,並不需要修改EmailSender類中的原始碼。這不就做到了在不修改原始碼的前提下擴充套件了系統嗎。這樣迎合了里氏替換原則的原始定義。在程式裡面我使用的Member,但在執行的時候我並不是給Member類傳送郵件,而是給它的子類傳送郵件。

四、依賴倒轉原則

   簡單來說,這個原則就是要求我們做到一點:針對介面程式設計,不要針對實現程式設計。

      假如說,有一個狗Dog類,現在要使用這個類,一般的做法就是直接New一個Dog物件的例項(Dog d=new Dog()),這個時候我們就是在針對具體的類程式設計也就是針對實現程式設計,這個時候程式和Dog這個類之間就是緊耦合。那如何讓他針對抽象程式設計呢?

     給他定義一個抽象父類或者介面Animal,當使用這個類的時候我們可以這麼寫(Animal d=new Dog()),這個時候我們是針對Animal程式設計也就是針對抽象程式設計。同時實現了程式本身和Dog這個類的解耦,他們之間已經成了鬆耦合。


OK,說到這裡,簡單總結一下開閉原則,里氏代換原則,依賴倒轉原則之間的關係:開閉原則是目標,里氏代換原則是基礎,而依賴倒轉原則是手段。他們相輔相成,相互補充。共同使我們的軟體具有良好的擴充套件性。

五、介面隔離原則

   這個原則和第一個單一職責原則有點類似。介面隔離原則是用來控制介面的粒度的,單一職責原則是用來控制類的粒度的。介面

職責原則指的是介面不能太大,如果接口裡面的方法很多,我麼可以考慮將這個介面分成一些更細小介面,一個介面只讓它承擔一

類職責或者一類角色即可。這個原則在這裡就不多解釋了。

六、合成複用原則

 

    這個原則要求我們儘量用組合關係達到複用,而不是使用繼承。繼承複用有一定的侷限性,比如說他會把基類的實現暴露給子

類,如果基類發生改變那麼它的所有子類都要發生改變。而組合複用恰恰解決了這些問題,相對於繼承來說,組合複用的耦合度較

低。而且可以在執行時動態程式設計。這個原則我可能也理解的不透徹,就只能說到這裡了。

七、迪米特法則

   這個原則的定義是每一個軟體單位對其他的單位都只有最少的知識,而且侷限於那些與本單位密切相關的軟體單位。

     通俗一點理解吧,我們開發的軟體會包含很多模組,他們相互直接也有一定的聯絡。兒迪米特法則要求:各個模組之間能沒有聯絡的話儘量沒有聯絡,能不發生互動的話就不要讓它們之間發生互動。這樣當其中一個模組發生修改是,可以儘量少的影響到其他模組。


    下一篇中講給大家講解簡單工廠模式。