C#面向對象設計模式縱橫談一之面向對象設計模式與原則

一)設計模式簡介程序員

1)每個模式描述了一個在咱們周圍不斷重複發生的問題,以及該問題的解決方案的核心。----Chirstopher Alexander算法

2)設計模式描述了軟件設計過程當中某一類常見問題的通常性的解決方案。編程

3)面向對象設計模式描述了面向對象設計過程當中、特定場景下、類與相互通訊的對象之間常見的組織關係。設計模式

 

二)GoF 23種設計模式編程語言

1)歷史性著做《設計模式:可複用面向對象軟件的基礎》一書中描述了23種經典面向對象設計模式,創立了模式在軟件設計中的地位。該書四位做者被人們並稱爲Gang of Four(GoF),「四人組」,該書描述的23種經典設計模式又被人們稱爲GoF 23種設計模式。ide

2)因爲《設計模式:可複用面向對象軟件的基礎》一書肯定了設計模式的地位,人們一般所說的設計模式隱含地表示「面向對象設計模式」。但這並不意味着「設計模式」就等於「面向對象設計模式」,也不意味着GoF 23種模式就表示了全部的「面向對象設計模式」。除了「面向對象設計模式」外,還有其餘設計模式。除了GoF 23種設計模式外,還有更多的面向對象設計模式。學習

3)GoF 23種設計模式是學習面向對象設計模式的起眯,而非終點。spa

 

三)設計模式與面向對象設計

1)面向對象設計模式解決的是「類與相互通訊的對象之間的組織關係」,包括它們的角色、職責、協做方式幾個方面。code

2)面向對象設計模式是「好的面向對象設計」,所謂「好的面向對象設計」是那些能夠知足「應對變化,提升複用」的設計。

3)面向對象設計模式描述的是軟件設計,所以它是獨立於編程語言的,可是面向對象設計模式的最終實現仍然要使用面向對象編程語言來表達。

4)面向對象設計模式不像算法技巧,能夠照搬照用,它是創建在對「面向對象」純熟、深刻的理解的基礎上的經驗性認識。撐握面向對象設計模式的前提是首先撐握「面向對象」。

 

四)從編程語言直觀瞭解面向對象

1)各類面向對象編程語言相互有別,但都能看到它們對面向對象三大機制的支持,即「封裝、繼承、多態」

a)封裝,隱藏內部實現

b)繼承,複用現有代碼

c)多態,改寫對象行爲

 

2)使用面向對象編程語言(如:C#),能夠推進程序中以面向對象的思惟來思考軟件設計結構,從而強化面向編程範式。

3)C#是一門支持面向對象編程的優秀語言,包括:各類級別封裝支持:單實現繼承+多接口實現;抽象方法與虛方法重寫。

 

五)但OOPL並不是面向對象的所有

1)經過面向對象編程語言(OOPL)認識到的面向對象,並非面向對象的所有,甚至只是淺陋的面向對象。

2)OOPL的三大機制「封裝、繼承、多態」能夠表達面向對象的全部概念,但這三大機制自己並無刻畫出面向對象的核心精神。換言之,便可以用這三大機制作出「好的面向對象設計」,也能夠用這三大機制作出「差的面向對象設計」。不是使用了面向對象的語言(例如:C#),就實現了面向對象的設計與開發!所以咱們不能依賴編程語言的面向對象機制,來掌握面向對象。

3)OOPL沒有回答面向對象的根本性問題——咱們爲何要使用面向對象?咱們應該怎樣使用三大機制來實現「好的面向對象」?咱們應該遵循什麼樣的面向對象原則?

4)任何一個嚴肅的面向對象程序員(如:C#程序員),都須要系統地學習面向對象的知識,單純從編程語言上得到的面向對象知識,不可以勝任面向對象設計與開發。

 

六)從一個示例談起

場景:咱們須要設計一我的事管理系統,其中的一個功能是對各類不一樣類型的員工,計算其當月的工資——不一樣類型的員工,擁有不一樣的薪金計算制度。

 

結構化作法:

1)得到人事系統中全部可能的員工類型

2)根據不一樣的員工類型所對應的不一樣的薪金制度,計算其工資

enum EmployeeType
        { 
            Engineer,
            Sales,
            Manager
        }

         private  static  decimal GetSalary(EmployeeType et)
        {
             if (et == EmployeeType.Engineer)
            { 
                
            }
             else  if (et == EmployeeType.Manager)
            { 
                
            }
             else  if (et == EmployeeType.Sales)
            { 
                
            }

             return  0.0M;
        }

面向對象設計:

1)根據沒的員工類型設計不一樣的類,並使這些類繼承自一個Employee抽象類,其中有一個抽象方法GetSalary。

2)在各個不一樣的員工類中,根據本身的薪金制度,重寫(override)

public  class Program
    {
         public  static  void Main( string[] args)
        {
            Employee e = EmployeeFactory.GetEmployee( 1);
            Console.WriteLine(e.GetSalary());
        }
    }

     public  class EmployeeFactory
    { 
         public  static Employee GetEmployee( int groupId)
        {
             if (groupId ==  0)
                 return  new Manager();
             else  if (groupId ==  1)
                 return  new Sales();
             else  if (groupId ==  2)
                 return  new Engineer();

             return  null;
        }
    }

     ///   <summary>
    
///  員工抽象類
    
///   </summary>
     abstract  class Employee
    {
         ///   <summary>
        
///  計算工資
        
///   </summary>
        
///   <returns></returns>
         public  abstract  decimal GetSalary();
    }

     ///   <summary>
    
///  普通員工類
    
///   </summary>
     class Engineer : Employee
    {
         ///   <summary>
        
///  計算工資
        
///   </summary>
        
///   <returns></returns>
         public  override  decimal GetSalary()
        {
             throw  new NotImplementedException();
        }
    }

     ///   <summary>
    
///  銷售員類
    
///   </summary>
     class Sales : Employee
    {
         ///   <summary>
        
///  計算工資
        
///   </summary>
        
///   <returns></returns>
         public  override  decimal GetSalary()
        {
             throw  new NotImplementedException();
        }
    }

     ///   <summary>
    
///  管理員類
    
///   </summary>
     class Manager : Employee
    {
         ///   <summary>
        
///  計算工資
        
///   </summary>
        
///   <returns></returns>
         public  override  decimal GetSalary()
        {
             throw  new NotImplementedException();
        }
    }

七)如今需求改變了

場景:隨着客戶公司業務規模的拓展,又出現了更多類型的員工,好比鐘點工,計件工等等,這對人事管理系統提出了挑戰——原有的程序必須改變。

 

結構化作法:

幾乎全部涉及到員工類型的地方(固然包括「計算工資程序」)都須要作改變變,這些代碼都須要從新編譯,從新部署......

 

面向對象作法:

只須要在新的文件裏增添新的員工類,讓其繼承自Employee抽象類,並重寫 GetSalary()方法,而後在 EmployeeFactory.GetEmployee方法中根據相關條件,產生新的員工類型就能夠了。其餘地方(顯示工資程序、Engineer類、 Sales類等)則不須要任何改變。

 

八)從新認識面向對象

1)對於前面的例子,從宏觀層面來看,面向對象的構建方式更能適應軟件的變化,能將變化所帶來的影響減爲最小

2)從微觀層面來看,面向對象的方式更強調各個類的「責任」,新增員工類型不會影響原來員工類型的實現代碼——這更符合真實的世界,也更能控制變化所影響的範圍,畢竟Engineer類不該該爲新增的「鐘點」來買單...

3)對象是什麼?

a)從概念層面講,對象是某種擁有責任的抽象。

b)從規格層面講,對象是一系列能夠被其餘對象使用的公共接口。

c)從語言實現層面來看,對象封裝了代碼和數據。

4)有了這些認識以後,怎樣才能設計「好的面向對象」?

a)遵循必定的面向對象設計原則

b)熟悉一些典型的面向對象設計模式

 

九)從設計原則到設計模式

1)針對接口編程,而不是針對實現編程

客戶無需知道所使用對象的特定類型,只須要對象擁有客戶所指望的接口。

2)優先使用對象組合,而不是繼承

類繼承一般爲「白箱複用」,對象組合一般爲「黑箱複用」。繼承在某種程序上破壞了封裝性,子類父類耦合度高;而對象組合則只要求被組合的對象具備良好定義的接口,耦合度低。

3)封裝變化點

使用封裝來建立對象之間的分界層,讓設計者能夠在分界層的一側進行修改,而不會對另外一側產生不良的影響,從而實現層次間的鬆耦合。

4)使用重構獲得模式

設計模式的應用不宜先入爲主,一上來就使用設計模式是以設計模式的最大誤用。沒有一步到位的設計模式。敏捷軟件開發實踐提倡的"Refactoring to Patterns"是目前普通公認的最好的使用設計模式的方法。

 

十)幾條更具體的設計原則

1)單一職責原則(SRP)

一個類應該僅有一個引發它變化的緣由

2)開放封閉原則(OCP)

類模塊應該是可擴展的,可是不可修改(對擴展開放,對更改封閉)

3)Liskov替換原則(LSP)

子類必須可以替換它們的基類

4)依賴倒置原則(DIP)

高層模塊不該該依賴於低層模塊,兩者都應該依賴於抽象。

抽象不該該依賴於實現細節,實現細節應該依賴於抽象。

5)接口隔離原則(ISP)

不該該強迫客戶程序依賴於它們不用的方法。

 

面向對象設計模式與原則總結

1)設計模式描述了軟件設計過程當中某一類常見問題的通常性解決方案。面向對象設計模式描述了面向對象設計過程當中、特定場景下、類與相互通訊的對象之間常見的組織關係。

2)深入理解面向對象是學好設計模式的基礎,掌握必定的面向對象設計原則才能把握面向對象設計模式的精髓,從而實現靈活運用設計模式。

3)三大基本面向對象設計原則:

a)針對接口編程,而不是針對實現編程

b)優先使用對象組合,而不是類繼承。

c)封裝變化點

4)使用重構獲得模式。敏捷軟件開發實踐提倡的"Refactoring to Patterns"是目前廣泛公認的最好的使用設計模式的方法。

相關文章
相關標籤/搜索