C#軟體設計——小話設計模式原則之:介面隔離原則ISP
前言:有朋友問我,設計模式原則這些東西在園子裡都討論爛了,一搜一大把的資料,還花這麼大力氣去整這個幹嘛。博主不得不承認,園子裡確實很多這方面的文章,並且不乏出色的博文。博主的想法是,既然要完善知識體系,就不能半途而廢。今天就來看看設計模式原則的另一個:介面隔離原則。
軟體設計原則系列文章索引
一、原理介紹
1、官方定義
介面隔離原則,英文縮寫ISP,全稱Interface Segregation Principle。
原始定義:Clients should not be forced to depend upon interfaces that they don't use,還有一種定義是The dependency of one class to another one should depend on the smallest possible interface。
官方翻譯:其一是不應該強行要求客戶端依賴於它們不用的介面;其二是類之間的依賴應該建立在最小的介面上面。簡單點說,客戶端需要什麼功能,就提供什麼介面,對於客戶端不需要的介面不應該強行要求其依賴;類之間的依賴應該建立在最小的介面上面,這裡最小的粒度取決於單一職責原則的劃分。
2、自己理解
2.1、原理解釋
- 不應該強行要求客戶端依賴於它們不用的介面。語句很好理解,即客戶端需要什麼介面,就依賴什麼介面,不需要的就不依賴。那麼我們反過來說,如果客戶端依賴了它們不需要的介面,那麼這些客戶端程式就面臨不需要的介面變更引起的客戶端變更的風險,這樣就會增加客戶端和介面之間的耦合程度,顯然與“高內聚、低耦合”的思想相矛盾。
- 類之間的依賴應該建立在最小的介面上面。何為最小的介面,即能夠滿足專案需求的相似功能作為一個介面,這樣設計主要就是為了“高內聚”。那麼我們如何設計最小的介面呢?那就要說說粒度的劃分了,粒度細化的程度取決於我們上一章講的的單一職責原則裡面介面劃分的粒度。從這一點來說,介面隔離和單一職責兩個原則有一定的相似性。
2.2、介面隔離原則和單一職責原則
從功能上來看,介面隔離和單一職責兩個原則具有一定的相似性。其實如果我們仔細想想還是有區別的。
(1)從原則約束的側重點來說,介面隔離原則更關注的是介面依賴程度的隔離,更加關注介面的“高內聚”;而單一職責原則更加註重的是介面職責的劃分。
(2)從介面的細化程度來說,單一職責原則對介面的劃分更加精細,而介面隔離原則注重的是相同功能的介面的隔離。介面隔離裡面的最小介面有時可以是多個單一職責的公共介面。
(3)單一職責原則更加偏向對業務的約束,介面隔離原則更加偏向設計架構的約束。這個應該好理解,職責是根據業務功能來劃分的,所以單一原則更加偏向業務;而介面隔離更多是為了“高內聚”,偏向架構的設計。
二、場景示例
下面就以訂單的操作為例來說明下介面隔離的必要性。
1、胖介面
軟體設計最初,我們的想法是相同功能的方法放在同一個接口裡面,如下,所有訂單的操作都放在訂單介面IOrder裡面。理論上來說,這貌似沒錯。我們來看看如何設計。
public interface IOrder { //訂單申請操作 void Apply(object order); //訂單稽核操作 void Approve(object order); //訂單結束操作 void End(object order); }
剛開始只有銷售訂單,我們只需要實現這個介面就好了。
public class SaleOrder:IOrder { public void Apply(object order) { throw new NotImplementedException(); } public void Approve(object order) { throw new NotImplementedException(); } public void End(object order) { throw new NotImplementedException(); } }
後來,隨著系統的不斷擴充套件,我們需要加入生產訂單,生產訂單也有一些單獨的介面方法,比如:排產、凍結、匯入、匯出等操作。於是我們向訂單的接口裡面繼續加入這些方法。於是訂單的介面變成這樣:
public interface IOrder { //訂單申請操作 void Apply(object order); //訂單稽核操作 void Approve(object order); //訂單結束操作 void End(object order); //訂單下發操作 void PlantProduct(object order);
//訂單凍結操作 void Hold(object order); //訂單刪除操作 void Delete(object order); //訂單匯入操作 void Import(); //訂單匯出操作 void Export(); }
我們生產訂單的實現類如下
//生產訂單實現類 public class ProduceOrder : IOrder { /// <summary> /// 對於生產訂單來說無用的介面 /// </summary> /// <param name="order"></param> public void Apply(object order) { throw new NotImplementedException(); } /// <summary> /// 對於生產訂單來說無用的介面 /// </summary> /// <param name="order"></param> public void Approve(object order) { throw new NotImplementedException(); } /// <summary> /// 對於生產訂單來說無用的介面 /// </summary> /// <param name="order"></param> public void End(object order) { throw new NotImplementedException(); } public void PlantProduct(object order) { Console.WriteLine("訂單下發排產"); }
public void Hold(object order) { Console.WriteLine("訂單凍結"); } public void Delete(object order) { Console.WriteLine("訂單刪除"); } public void Import() { Console.WriteLine("訂單匯入"); } public void Export() { Console.WriteLine("訂單匯出"); } }
銷售訂單的實現類也要相應做修改
//銷售訂單實現類 public class SaleOrder:IOrder { public void Apply(object order) { Console.WriteLine("訂單申請"); } public void Approve(object order) { Console.WriteLine("訂單稽核處理"); } public void End(object order) { Console.WriteLine("訂單結束"); } #region 對於銷售訂單無用的介面方法 public void PlantProduct(object order) { throw new NotImplementedException(); }
public void Hold(object order) { throw new NotImplementedException(); } public void Delete(object order) { throw new NotImplementedException(); } public void Import() { throw new NotImplementedException(); } public void Export() { throw new NotImplementedException(); } #endregion }
需求做完了,上線正常執行。貌似問題也不大。系統執行一段時間之後,新的需求變更來了,要求生成訂單需要一個訂單撤銷排產的功能,那麼我們的介面是不是就得增加一個訂單撤排的介面方法CancelProduct。於是乎介面變成這樣:
public interface IOrder { //訂單申請操作 void Apply(object order); //訂單稽核操作 void Approve(object order); //訂單結束操作 void End(object order); //訂單下發操作 void PlantProduct(object order); //訂單撤排操作 void CancelProduct(object order); //訂單凍結操作 void Hold(object order); //訂單刪除操作 void Delete(object order); //訂單匯入操作 void Import(); //訂單匯出操作 void Export(); }
這個時候問題就來了,我們的生產訂單隻要實現這個撤銷的介面貌似就OK了,但是我們的銷售訂單呢,本來銷售訂單這一塊我們不想做任何的變更,可是由於我們IOrder接口裡面增加了一個方法,銷售訂單的實現類是不是也必須要實現一個無效的介面方法?這就是我們常說的“胖介面”導致的問題。由於介面過“胖”,每一個實現類依賴了它們不需要的介面,使得層與層之間的耦合度增加,結果導致了不需要的介面發生變化時,實現類也不得不相應的發生改變。這裡就凸顯了我們介面隔離原則的必要性,下面我們就來看看如何通過介面隔離來解決上述問題。
2、介面隔離
我們將IOrder介面分成兩個介面來設計
//刪除訂單介面 public interface IProductOrder { //訂單下發操作 void PlantProduct(object order); //訂單撤排操作 void CancelProduct(object order); //訂單凍結操作 void Hold(object order); //訂單刪除操作 void Delete(object order); //訂單匯入操作 void Import(); //訂單匯出操作 void Export(); } //銷售訂單介面 public interface ISaleOrder { //訂單申請操作 void Apply(object order); //訂單稽核操作 void Approve(object order); //訂單結束操作 void End(object order); }
對應的實現類只需要實現自己需要的介面即可
//生產訂單實現類 public class ProduceOrder : IProductOrder { public void PlantProduct(object order) { Console.WriteLine("訂單下發排產"); } public void CancelProduct(object order) { Console.WriteLine("訂單撤排"); } public void Hold(object order) { Console.WriteLine("訂單凍結"); } public void Delete(object order) { Console.WriteLine("訂單刪除"); } public void Import() { Console.WriteLine("訂單匯入"); } public void Export() { Console.WriteLine("訂單匯出"); } } //銷售訂單實現類 public class SaleOrder : ISaleOrder { public void Apply(object order) { Console.WriteLine("訂單申請"); } public void Approve(object order) { Console.WriteLine("訂單稽核處理"); } public void End(object order) { Console.WriteLine("訂單結束"); } }
這樣設計就能完美解決上述“胖介面”導致的問題,如果需要增加訂單操作,只需要在對應的介面和實現類上面修改即可,這樣就不存在依賴不需要介面的情況。通過這種設計,降低了單個介面的複雜度,使得介面的“內聚性”更高,“耦合性”更低。由此可以看出介面隔離原則的必要性。
三、總結
通過以上訂單功能的優化,我們看到了介面隔離原則的必要性,當然,關於介面隔離原則和單一職責原則的細節我們也不必過多追究,不管何種原則,能解決我們的設計問題就是好的原則、我們必須遵守的原則。歡迎園友拍磚斧正。如果園友們覺得本文對你有幫助,請幫忙推薦,博主將繼續努力~~
相關推薦
C#軟體設計——小話設計模式原則之:介面隔離原則ISP
前言:有朋友問我,設計模式原則這些東西在園子裡都討論爛了,一搜一大把的資料,還花這麼大力氣去整這個幹嘛。博主不得不承認,園子裡確實很多這方面的文章,並且不乏出色的博文。博主的想法是,既然要完善知識體系,就不能半途而廢。今天就來看看設計模式原則的另一個:介面隔離原則。 軟體設計原則系列文章索引 一、原理
C#軟體設計——小話設計模式原則之:開閉原則OCP
前言:這篇繼續來看看開閉原則。廢話少說,直接入正題。 軟體設計原則系列文章索引 一、原理介紹 1、官方定義 開閉原則,英文縮寫OCP,全稱Open Closed Principle。 原始定義:Software entities (classes, modules, functions) sho
C#軟體設計——小話設計模式原則之:單一職責原則SRP
前言:上篇C#軟體設計——小話設計模式原則之:依賴倒置原則DIP簡單介紹了下依賴倒置的由來以及使用,中間插了兩篇WebApi的文章,這篇還是迴歸正題,繼續來寫寫設計模式另一個重要的原則:單一職責原則。 軟體設計原則系列文章索引 一、原理介紹 1、官方定義 單一職責原則,英文縮寫SRP,全稱Sing
C#軟體設計——小話設計模式原則之:依賴倒置原則DIP
前言:很久之前就想動筆總結下關於軟體設計的一些原則,或者說是設計模式的一些原則,奈何被各種bootstrap元件所吸引,一直抽不開身。群裡面有朋友問博主是否改行做前端了,呵呵,其實博主是想做“全戰”,即各方便都有戰鬥力。關於設計模式,作為程式猿的我們肯定都不陌生。博主的理解,所謂設計模式就是前人總結下來的一些
小話設計模式原則之:單一職責原則SRP(C#篇)
正文 前言:上篇C#軟體設計——小話設計模式原則之:依賴倒置原則DIP簡單介紹了下依賴倒置的由來以及使用,中間插了兩篇WebApi的文章,這篇還是迴歸正題,繼續來寫寫設計模式另一個重要的原則:單一職責原則。 軟體設計原則系列文章索引 回到頂部 一、原理介紹 回到頂部
【學習筆記】慕課網—Java設計模式精講 第3章 軟體設計七大原則-3-5 介面隔離原則
/** * 軟體設計七大原則-介面隔離原則 學習筆記 * @author cnRicky * @date 2018.11.10 */ 介面隔離原則 定義:用多個專門的介面,而不使用單一的總介面,客戶端不應該依賴它不需要的介面 一個類對一個類的依賴應該建立在最小的介面上 建立單一介
設計模式原則:介面隔離原則
設計模式原則:介面隔離原則 介面隔離原則: 客戶端不應該依賴它不需要的介面;一個類對另一個類的依賴應該建立在最小的介面上。 (圖片來自網路) 見上圖,該把介面細分到3個介面中去,保證每個類都只實現它需要的介面。 介面隔離原則與單一職責原則有什麼區別呢? 單一職責原則,是指
設計模式六大原則(4):介面隔離原則
定義:客戶端不應該依賴它不需要的介面;一個類對另一個類的依賴應該建立在最小的介面上。 問題由來:類A通過介面I依賴類B,類C通過介面I依賴類D,如果介面I對於類A和類B來說不是最小介面,則類B和類D必須去實現他們不需要的方法。 解決方案:將臃腫的介面I拆分為獨立的幾個介面,
設計模式系列:介面隔離原則
問題由來 問題由來:類A通過介面I依賴類B,類C通過介面I依賴類D,如果介面I對於類A和類B來說不是最小介面,則類B和類D必須去實現他們不需要的方法。 解決方案:將臃腫的介面I拆分為獨立的幾個介面,類A和類C分別與他們需要的介面建立依賴關係。也就是採用介面隔
設計模式個人總結,介面隔離原則總結
總結經驗 近期自學Unity引擎,學到了關於設計模式這一塊,以前學習Java多次接觸設計模式,也在應用的開發過程中頻繁使用。雖然開發過程中沒有特意去強調使用設計模式,但設計模式的使用總是潛移默化的,
設計模式六大原則4---》介面隔離原則
定義:客戶端不應該依賴它不需要的介面;一個類對另一個類的依賴應該建立在最小的介面上;問題由來:類A通過介面I依賴B,類C通過介面I依賴D,如果介面I對於類A和類B來說不是最小介面,則類B和類D必須去實現他們不需要的方法。解決方案:將臃腫的介面I拆分為獨立的幾個介面,類A和類C
6大設計原則之接口隔離原則
設計時 接口 老師 規範 模塊 一個個 on() 獨立 alt 接口隔離原則的定義 什麽是接口. 實例接口,比如定義了一個Person類,然後 Person p = new Pserson(); 產生一個實例,Person類就是 p 的接口 類接口,就是Java中使用 i
設計模式六大原則之裏氏替換原則
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]:開閉原則
說了 一點 模塊 活性 問題 單一職責原則 就是 認識 適應 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行
設計模式(八)面向對象設計原則之合成復用原則
擴展 會有 作者 如果 composite info 繼承 裏氏代換原則 oracle數據 引用自:http://blog.csdn.net/lovelion 作者:劉偉 合成復用原則(Composite Reuse Principle, CRP):盡量使用對象組合,
學習設計模式 - 六大基本原則之裏氏替換原則
bili 傳遞 如何使用 兼容 秦小波 ati ace 繼續 pointer 設計模式總共有六大基本原則,統稱為SOLID (穩定)原則,分別是S-單一職責原則(Single Responsibility Principle), O-開閉原則(Open closed P
設計模式六大原則例子(一)-- 介面隔離原則(ISP)例子
之前我們對設計模式的六大原則做了簡單歸納,這篇部落格是對介面隔離原則進行的舉例說明。 1介面隔離原則的意義 建立單一介面,不要建立龐大臃腫的介面,儘量細化介面,介面中的方法儘量少。也就是說,我們要為各個類建立專用的介面,而不要試圖去建立一個很龐大的介面供所有依賴它的類去呼叫。 在程式設計中,依賴幾個
設計模式六大原則(一)-- 介面隔離原則(ISP)
設計圖和原始碼請訪問作者的github:https://github.com/yangsheng20080808/DesignModel From Now On,Let us begin Design Patterns。 介面隔離原則 Interface Segregati