一. 接口隔離原則
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; } }
經紀人

/// <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() + "洽淡業務。"); } }
測試
{ 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 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。