第三節:接口隔離原則、迪米特法則、組合聚合原則


一. 接口隔離原則

1. 定義

 一個類對另一個類的依賴應該建立在最小的接口上,不應該依賴他不需要的接口。

 通俗的說:要為每個類建立它們需要的專用接口,而不要試圖去建立一個很龐大的接口供所有依賴它的類去調用。

與單一職責原則的區別:

(1). 單一職責原則注重的是職責,而接口隔離原則注重的是對接口依賴的隔離。

(2). 單一職責原則主要是約束類,它針對的是程序中的實現和細節;接口隔離原則主要約束接口,主要針對抽象和程序整體框架的構建。

2. 優點

  接口隔離原則是為了約束接口、降低類對接口的依賴性,遵循接口隔離原則有以下 優點:

 (1). 將臃腫龐大的接口分解為多個粒度小的接口,可以預防外來變更的擴散,提高系統的靈活性和可維護性。

 (2). 接口隔離提高了系統的內聚性,減少了對外交互,降低了系統的耦合性。

 (3). 如果接口的粒度大小定義合理,能夠保證系統的穩定性;但是,如果定義過小,則會造成接口數量過多,使設計復雜化;如果定義太大,靈活性降低,無法提供定制服務,給整體項目帶來無法預料的風險。

 (4). 使用多個專門的接口還能夠體現對象的層次,因為可以通過接口的繼承,實現對總接口的定義。

 (5). 能減少項目工程中的代碼冗余。過大的大接口里面通常放置許多不用的方法,當實現這個接口的時候,被迫設計冗余的代碼。

3. 實現方法和案例

(1). 實現方法

 A. 接口盡量小,但是要有限度。一個接口只服務於一個子模塊或業務邏輯。

 B. 為依賴接口的類定制服務。只提供調用者需要的方法,屏蔽不需要的方法。

 C. 了解環境,拒絕盲從。每個項目或產品都有選定的環境因素,環境不同,接口拆分的標准就不同深入了解業務邏輯。

 D. 提高內聚,減少對外交互。使接口用最少的方法去完成最多的事情。

(2). 案例

 在成績管理系統中,會有很多業務,這里拆分出來多個接口,分別是:輸入模塊接口、統計模塊接口、打印模塊接口,需要哪個接口就去實現哪個接口。

   /// <summary>
   /// 基礎模塊接口 
   /// </summary>
    public interface IBasicModel
    {
        void insert();
        void delete();
        void modify();
    }
    /// <summary>
    /// 統計模塊接口
    /// </summary>
    public interface ICountModule
    {
        void countTotalScore();
        void countAverage();
    }
    /// <summary>
    /// 打印模塊接口
    /// </summary>
    public interface IPrintModule
    {
        void printStuInfo();
        void queryStuInfo();
    }

 

 

二. 迪米特法則

1. 定義

 又叫:最小知道原則。

 其含義:如果兩個軟件實體無須直接通信,那么就不應當發生直接的相互調用,可以通過第三方轉發該調用。 通俗的來說:只與你的直接朋友交談,不跟“陌生人”說話。

   目的:降低類之間的耦合度,提高模塊的相對獨立性。

進一步解析:

 (1). 從依賴者的角度來說,只依賴應該依賴的對象。

 (2). 從被依賴者的角度說,只暴露應該暴露的方法。

2. 優點

 (1). 降低了類之間的耦合度,提高了模塊的相對獨立性。

 (2). 由於親合度降低,從而提高了類的可復用率和系統的擴展性。

同樣也有弊端:

 過度使用迪米特法則會使系統產生大量的中介類,從而增加系統的復雜性,使模塊之間的通信效率降低。所以,在釆用迪米特法則時需要反復權衡,確保高內聚和低耦合的同時,保證系統的結構清晰。

3. 實現方法和案例

(1). 實現方法

 A. 在類的划分上,應該創建弱耦合的類。類與類之間的耦合越弱,就越有利於實現可復用的目標。

 B. 在類的結構設計上,盡量降低類成員的訪問權限。

 C. 在類的設計上,優先考慮將一個類設置成不變類。

 D. 在對其他類的引用上,將引用其他對象的次數降到最低。

 E. 不暴露類的屬性成員,而應該提供相應的訪問器(set 和 get 方法)。

 F. 謹慎使用序列化(Serializable)功能。

(2). 案例

 明星 ----- 經紀人 ------ 粉絲、媒體;  明星不直接和粉絲、媒體打交道,都是通過經紀人來打交道。

明星和粉絲、媒體類

   /// <summary>
    /// 粉絲類
    /// </summary>
    public class Fans
    {
        private String name;
        public Fans(String name)
        {
            this.name = name;
        }
        public String getName()
        {
            return name;
        }
    }
    /// <summary>
    /// 媒體公司類
    /// </summary>
    public class Company
    {
        private String name;
        public Company(String name)
        {
            this.name = name;
        }
        public String getName()
        {
            return name;
        }
    }
   /// <summary>
    /// 明星類
    /// </summary>
    public class Star
    {
        private String name;
        public Star(String name)
        {
            this.name = name;
        }
        public String getName()
        {
            return name;
        }
    }
View Code

經紀人

/// <summary>
    /// 經紀人類
    /// </summary>
    public class Agent
    {
        private Star myStar;
        private Fans myFans;
        private Company myCompany;
        public void setStar(Star myStar)
        {
            this.myStar = myStar;
        }
        public void setFans(Fans myFans)
        {
            this.myFans = myFans;
        }
        public void setCompany(Company myCompany)
        {
            this.myCompany = myCompany;
        }
        public void meeting()
        {
            Console.WriteLine(myFans.getName() + "與明星" + myStar.getName() + "見面了。");
        }
        public void business()
        {
            Console.WriteLine(myCompany.getName() + "與明星" + myStar.getName() + "洽淡業務。");
        }
    }
View Code

測試

            {
                Console.WriteLine("--------------------------迪米特法則--------------------------------");
                //明星 ----- 經紀人 ------ 粉絲、媒體;  明星不直接和粉絲、媒體打交道,都是通過經紀人來打交道
                Agent agent = new Agent();
                agent.setStar(new Star("呂餃子"));
                agent.setFans(new Fans("粉絲李馬茹"));
                agent.setCompany(new Company("中國傳媒有限公司"));
                agent.meeting();
                agent.business();
            }

運行結果

 

 

三. 組合聚合原則

1. 定義

  也叫合成復用原則,指的是軟件在復用的時候,優先使用組合和聚合的關系來實現,其次才是繼承關系。

PS:如果要使用繼承關系,則必須嚴格遵循里氏替換原則。合成復用原則同里氏替換原則相輔相成的,兩者都是開閉原則的具體實現規范。

擴展:適配器模式中的類適配模式,是通過繼承的方式實現的;對象適配模式,是通過組合的方式實現的。

2. 優點

繼承復用存在以下缺點:

 (1). 繼承復用破壞了類的封裝性。因為繼承會將父類的實現細節暴露給子類,父類對子類是透明的,所以這種復用又稱為“白箱”復用。

 (2). 子類與父類的耦合度高。父類的實現的任何改變都會導致子類的實現發生變化,這不利於類的擴展與維護。

 (3). 它限制了復用的靈活性。從父類繼承而來的實現是靜態的,在編譯時已經定義,所以在運行時不可能發生變化。

組合聚合復用存在以下優點:

 (1). 它維持了類的封裝性。因為成分對象的內部細節是新對象看不見的,所以這種復用又稱為“黑箱”復用。

 (2). 新舊類之間的耦合度低。這種復用所需的依賴較少,新對象存取成分對象的唯一方法是通過成分對象的接口。

 (3). 復用的靈活性高。這種復用可以在運行時動態進行,新對象可以動態地引用與成分對象類型相同的對象。

3. 實現方法和案例

(1). 實現方法

 組合聚合原則是通過將已有的對象納入新對象中,作為新對象的成員對象來實現的,新對象可以調用已有對象的功能,從而達到復用。

(2). 案例

相關類

    /// <summary>
    /// 封裝最基本的四則運算方法
    /// </summary>
    public class MyBaseHelp
    {

        public int Add(int a,int b)
        {
            return a + b;
        }

        public int Multiply(int a, int b)
        {
            return a * b;
        }

    }
 public class MyChildHelp1
    {
        //復用原則
        public MyBaseHelp _baseHelp;
        public MyChildHelp1()
        {
            _baseHelp = new MyBaseHelp();
        }

        /// <summary>
        /// 特殊計算
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public int SpecialCalculate(int a, int b)
        {
            return _baseHelp.Add(a, b) + _baseHelp.Multiply(a, b);
        }

    }

測試

          Console.WriteLine("--------------------------組合聚合原則--------------------------------");
                MyChildHelp1 help1 = new MyChildHelp1();
                Console.WriteLine($"特殊運算結果為:{help1.SpecialCalculate(10, 4)}");  

 

運行結果

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM