介面隔離原則

来源:https://www.cnblogs.com/liebrother/archive/2019/01/04/10222756.html
-Advertisement-
Play Games

個人博客原文: "介面隔離原則" 設計模式六大原則之四:介面隔離原則。 簡介 姓名 :介面隔離原則 英文名 :Interface Segregation Principle 價值觀 :寧缺毋濫 個人介紹 : 1. Clients should not be forced to depend upon ...


個人博客原文:
介面隔離原則

景

設計模式六大原則之四:介面隔離原則。

簡介

姓名 :介面隔離原則

英文名 :Interface Segregation Principle

價值觀 :寧缺毋濫

個人介紹

  1. Clients should not be forced to depend upon interfaces that they don't use.(客戶端不應該依賴它不需要的介面。)
  2. The dependency of one class to another one should depend on the smallest possible interface.(類間的依賴關係應該建立在最小的介面上。)

也用一個故事來講這 2 句乾巴巴的定義。

一小伙子跑到大城市的工廠打工,工作了一年半載,越來越覺得沒勁,每天干那麼多活,又領那麼一點工資,和他老爸抱怨這段時間的困擾,老爸想著,家裡有個小作坊,自己也一年不如一年了,要不就讓兒子回老家管理這小作坊。小伙子熬不過這個年,就跑回老家跟著老爸打理小作坊。

布娃娃
(來自Google Image)

小作坊主要是做布娃娃的,如上圖,工作在於打扮包裝布娃娃,工序有給布娃娃扎辮子、穿衣服、包裝入箱、打標簽。整個完整的流程都是一個人做的。有很多個工人每天都在做這個事情。

老爸向小伙子訴苦,感覺招工挺多人的,生產力還是提不上去。小伙子記著老爸的話,在工廠裡面觀察了幾天,他發現每個工人都要做這 4 個打扮包裝布娃娃的工序,有些工人扎辮子很快但穿衣服很慢,有些工人扎辮子很慢但穿衣服快,他用了筆記本記下來:李大姨扎辮子快,王大媽穿衣服快,就這樣把每個人有效率的工作都記錄下來。

一天晚上吃飯,小伙子跟老爸說了自己觀察到的現象,也把本子拿給老爸看,跟老爸商量:可不可以做個嘗試,不要每個人負責打扮包裝布娃娃全步驟,而是按工序分開,每個人只負責一個工序,每個工人只乾一件事,更容易熟能生巧。老爸聽著覺得有道理。

第二天早上,就到小作坊里,召集了所有工人,按小伙子的筆記上面的名單分工,大家都做好各自負責的內容,像流水線一樣,做好了就放到下個工序的地方,讓下個工序的人去做。到了下班,小伙子清點了今天工作的成果,包裝完成的娃娃比前一天多了 50% 。晚上小伙子跟老爸喝著百威吃起大肉慶祝一番。

這個故事你看了可能想罵爹罵娘,跟上面的定義有啥毛關係?故事只是把大家帶入這個場景,我們在工作中,著手開發之前不都得先理清好需求背景,這就是要講介面隔離原則的背景,通過代碼來給大家講解一下如何用好介面隔離原則。

父親的運營模式

先看代碼

interface Work {

    void hairBraiding();
    void getDressed();
    void packingIntoTheBox();
    void makeTag();

}

class WangMather implements Work{

    @Override
    public void hairBraiding() {
        System.out.println("王大媽給布娃娃扎辮子");
    }

    @Override
    public void getDressed() {
        System.out.println("王大媽給布娃娃穿衣服");
    }

    @Override
    public void packingIntoTheBox() {
        System.out.println("王大媽把布娃娃裝入箱子");
    }

    @Override
    public void makeTag() {
        System.out.println("王大媽給箱子打標簽");
    }
}

class LiAunt implements Work {

    @Override
    public void hairBraiding() {
        System.out.println("李大姨給布娃娃扎辮子");
    }

    @Override
    public void getDressed() {
        System.out.println("李大姨給布娃娃穿衣服");
    }

    @Override
    public void packingIntoTheBox() {
        System.out.println("李大姨把布娃娃裝入箱子");
    }

    @Override
    public void makeTag() {
        System.out.println("李大姨給箱子打標簽");
    }
}

// 測試代碼
WangMather wangMather = new WangMather();
wangMather.hairBraiding();
wangMather.getDressed();
wangMather.packingIntoTheBox();
wangMather.makeTag();

LiAunt liAunt = new LiAunt();
liAunt.hairBraiding();
liAunt.getDressed();
liAunt.packingIntoTheBox();
liAunt.makeTag();

在父親管理下的小作坊,是大家各自完成好一個布娃娃,工作互不交接,在這種運營模式下,我們把所有工作都合併在一個介面 Work 是沒有問題的。有人可能要問,不是說介面隔離麽?這裡面 Work 介面的 4 個方法都可以分離開,它們都是各自的工作內容。稍等一下,我們現在是基於老父親運營的模式下實現,如果小作坊一直都是這種模式運營,這段代碼有問題麽?其實沒問題的,我們根據當時的業務考慮,在這種情況下,把 Work 抽成 4 個介面不是不可以,只是不現實,每個工人都去實現一模一樣的 4 個介面在老父親運營模式下是不切實際。

兒子的運營模式

接下來介紹兒子的運營模式。兒子提倡的是每個工人職責分明,只負責一個事情,在這種情況下,如果還是用老父親的 Work 介面會有什麼問題呢?上面我們說了,李大姨扎辮子快,王大媽穿衣服快,所以李大姨被分配去給布娃娃扎辮子,王大媽被分配去給布娃娃穿衣服。我們沿用老父親的 Work 介面實現,代碼如下

class WangMather2 implements Work{

    @Override
    public void hairBraiding() {
    }

    @Override
    public void getDressed() {
        System.out.println("王大媽給布娃娃穿衣服");
    }

    @Override
    public void packingIntoTheBox() {
    }

    @Override
    public void makeTag() {
    }
}

class LiAunt2 implements Work {

    @Override
    public void hairBraiding() {
        System.out.println("李大姨給布娃娃扎辮子");
    }

    @Override
    public void getDressed() {
    }

    @Override
    public void packingIntoTheBox() {
    }

    @Override
    public void makeTag() {
    }
}

看出問題來了麽?李大姨僅僅參與扎辮子工作,王大媽參與了穿衣服工作,但是卻都要依舊實現其他 3 個多餘的介面。所以在兒子的運營模式下,老父親的 Work 介面需要重新分配,以工序的角度分配,而不是以完成一個布娃娃的角度分配。總共有 4 個工序:扎辮子、穿衣服、包裝入箱、打標簽,我們需要定義 4 個介面,讓員工去實現各自負責的工序介面。代碼如下


interface Hair {
    void hairBraiding();
}

interface Dress {
    void getDressed();
}

interface Box {
    void packingIntoTheBox();
}

interface Tag {
    void makeTag();
}

/**
 * 李大姨給布娃娃扎辮子快
 */
class LiAunt3 implements Hair {

    @Override
    public void hairBraiding() {
        System.out.println("李大姨給布娃娃扎辮子");
    }
}

/**
 * 王大媽給布娃娃穿衣服快
 */
class WangMather3 implements Dress{

    @Override
    public void getDressed() {
        System.out.println("王大媽給布娃娃穿衣服");
    }

}

/**
 * 陳大叔包裝快
 */
class ChenUncle implements Box {

    @Override
    public void packingIntoTheBox() {
        System.out.println("陳大叔給布娃娃裝箱");
    }
}

/**
 * 黃大姐貼標簽快
 */
class HuangSister implements Tag {

    @Override
    public void makeTag() {
        System.out.println("黃大姐給箱子打標簽");
    }
}

// 測試代碼
LiAunt3 liAunt3 = new LiAunt3();
WangMather3 wangMather3 = new WangMather3();
ChenUncle chenUncle = new ChenUncle();
HuangSister huangSister = new HuangSister();
liAunt3.hairBraiding();
wangMather3.getDressed();
chenUncle.packingIntoTheBox();
huangSister.makeTag();

這段代碼看起來就很清晰了,在兒子的運營模式下,大家都是只做一道工序,這樣子實現就非常合理。看了這個過程,你理解了介面隔離原則了麽?再看一看上面的定義:客戶端不應該依賴它不需要的介面。閉上眼睛,靜默 3 秒,感受一下。
我們也可以回憶一下在工作中編寫的代碼,是不是有遵守介面隔離原則?在特定的場景下,如果很多類實現了同一個介面,並且都只實現了介面的極少部分方法,這時候很有可能就是介面隔離性不好,就要去分析能不能把方法拆分到不同的介面。

總結

介面隔離原則最最最重要一點就是要根據實際情況,具體業務具體分析,不能犯了上面說到的錯誤:在老父親的運營模式下,按兒子的工序劃分介面去實現,那樣子會得不償失。

參考資料:《大話設計模式》、《Java設計模式》、《設計模式之禪》、《研磨設計模式》、《Head First 設計模式》

希望文章對您有所幫助,設計模式系列會持續更新,感興趣的同學可以關註公眾號,第一時間獲取文章推送閱讀,也可以一起交流,交個朋友。

公眾號之設計模式系列文章

公眾號


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • jQuery 選擇器 jQuery 效果函數 jQuery 文檔操作方法 這些方法對於 XML 文檔和 HTML 文檔均是適用的,除了:html()。 jQuery 屬性操作方法 下麵列出的這些方法獲得或設置元素的 DOM 屬性。 這些方法對於 XML 文檔和 HTML 文檔均是適用的,除了:htm ...
  • isNaN(val) 當val為NaN的時候,isNaN(val)返回ture 當val不為NaN的時候,isNaN(val)返回false ...
  • 居中問題: 1.Fixed定位margin:0 auto;不管用,水平居中需要做如下處理: position: fixed; top: 0; bottom: 0; left: 0; right: 0; margin: auto; 2.relative定位margin:0 auto;管用,水平居中需要 ...
  • 本文由雲+社區發表 在一線做了十年的開發,經歷了網易、百度、騰訊研究院、MIG 等幾個地方,陸續做過 3D 游戲、2D 頁游、瀏覽器、移動端翻譯 app 等。 積累了一些感悟。必然有依然幼稚的地方,就當拋磚引玉,聊為笑談。 一、對於團隊而言,流程太重要了 行軍打仗,你需要一個嚮導;如果沒有嚮導,你需 ...
  • 本文記錄在自己學習js過程中,違反直覺,出乎意料,倍感震驚的知識點。當然,不瞭解這個知識點,很容易出錯,因為畢竟違反直覺,出乎意料,倍感震驚嘛! 1. 兩個內容一樣的數組竟然不相等? 知識點:對象引用,更詳細的介紹點這裡 2. 我們都知道,0.1+0.2等於0.3,但是js中 0.1+0.2 不等於 ...
  • 新年第一篇文章,先祝大家新年快樂!!那麼接下來進入正文。 前言 前陣子突發奇想,突然開始刷leetcode。其中刷到了一道有意思的題目,發現這道題是當時秋招的時候,騰訊面試官曾經問過我的題目。於是分享給大家看下。 題目描述 給定一個 非空 整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次 ...
  • 背景圖的繪製(大圓、數字、小圓點) 掌握基礎知識:圓的繪製(arc方法),關於圓的弧度的計算,數學中關於sin cos的用法 圓的弧度為2*Math.PI 12個數字分得弧度每個為2*Math.PI/12 那麼rad=i*2*Math.PI/12 x=Math.cos(rad)*所需要的長度(也就是 ...
  • init1(){return new Promise((resolve, reject) => { let data={ dateStr:this.time }; api.get('url', null).then( res => { //自己的操作 resolve() }).catch(err = ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...