介面隔離原則 | Interface Segregation Principle

Posted by Ian Tsai on Sunday, September 13, 2020

本系列文章同步分享於IT邦幫忙第12屆鐵人賽


Design Pattern 系列文章導讀


Design Pattern可以說是開發上大家都會遇到的一個課題, 這系列文會從Design Principles、各種design pattern到最後的Anti-Patterns & Code Smells介紹下去,讓我們可以更了解各種pattern的使用時機與場合。 預計目標主題如下,若有哪部分不熟的章節可以直接點進去看
註:可以利用Online Java Compiler IDE

  1. 設計模式 - 入門篇
  2. 設計模式 - 原則篇 | Design Principles
  3. 設計模式 - 創建型模型篇 | Creational Patterns
  4. 設計模式 - 結構型模型篇 | Structural Patterns
  5. 設計模式 - 行為型模型篇 | Behavioural Patterns
  6. 設計模式 - 番外篇
  • 定義


Clients should not be forced to depend on methods that they do not use.

翻譯年糕:客戶不應該被強迫依賴他們不使用的方法。

回想當我們在公司工作時,除了寫程式、抓bug,資深一點的或許還要做簡報…等等多元的工作內容,我們用程式來呈現我們的情況:

interface Skill{
    public void coding();
    public void debug();
    public void prepareSlides();
}
class SeniorEngineer implements Skill{
    public void coding(){
        System.out.println("當碼農!!");
    };
    public void debug(){
        System.out.println("找蟲!!");
    };
    public void prepareSlides(){
        System.out.println("做老闆的報告!!");
    };
}


public class Company {
    public static void main(String args[]) {
      SeniorEngineer se = new SeniorEngineer();
      System.out.println("SeniorEngineer 上班");
      se.coding();
      se.debug();
      se.debug();
    }
}

output

SeniorEngineer 上班
當碼農!!
找蟲!!
做老闆的報告!!

這段程式呈現了身為一個Senior Engineer,上班需要做的工作!!但這樣存在著什麼問題呢?

假如公司今天招募了一個Junior Engineer,如下:

interface Skill{
    public void coding();
    public void debug();
    public void prepareSlides();
}
class JuniorEngineer implements Skill{
    public void coding(){
        System.out.println("當碼農!!");
    };
    public void debug(){
        System.out.println("找蟲!!");
    };
    public void prepareSlides(){
        System.out.println("我不會做報告!!");
    };
}
public class Company {
    public static void main(String args[]) {
      JuniorEngineer je = new JuniorEngineer();
      System.out.println("SeniorEngineer 上班");
      je.coding();
      je.debug();
      je.prepareSlides();
    }
}

output

JuniorEngineer 上班
當碼農!!
找蟲!!
我不會做報告!!

剛報到的Junior Engineer,他會coding,也會debug,可是他並不會做簡報。但他一定要實作Skill介面的方法,那該怎麼辦?剛剛定義有提到,客戶不應該被強迫依賴他們不使用的方法。顯然這個整體規劃的需要做一些更改。可能是公司招聘需求是要會做簡報的工程師,不然就是公司要把這個技能條件拆分出來。

  • 實作Interface segregation principle


為了讓公司的員工分工明確一點,我們把Skill分成TechSkill以及OtherSkill

interface TechSkill{
    public void coding();
    public void debug();
}

interface OtherSkill{
    public void prepareSlides();
}

class SeniorEngineer implements TechSkill, OtherSkill{
    public void coding(){
        System.out.println("當碼農!!");
    };
    public void debug(){
        System.out.println("找蟲!!");
    };
    public void prepareSlides(){
        System.out.println("做老闆的報告!!");
    };
}

class JuniorEngineer implements TechSkill{
    public void coding(){
        System.out.println("當碼農!!");
    };
    public void debug(){
        System.out.println("找蟲!!");
    };
}
public class Company {
    public static void main(String args[]) {
      SeniorEngineer se = new SeniorEngineer();
      System.out.println("SeniorEngineer work");
      se.coding();
      se.debug();
      se.prepareSlides();
      
      JuniorEngineer je = new JuniorEngineer();
      System.out.println("JuniorEngineer work");
      je.coding();
      je.debug();
    }
}

output

SeniorEngineer work
當碼農!!
找蟲!!
做老闆的報告!!
JuniorEngineer work
當碼農!!
找蟲!!

重新設計後,Senior和Junior所應該要會的技能已經被分類,Junior不在需要實作他不會的技能,他只需要專心的做她份內的事。未來若OtherSkill內需要增加其他工作時也不會影響JuniorEngineer的工作!!!

我們來看看UML了解一下兩者結構上的差異:

上圖表示為我們原本的設計,如果把所有的技能都放在同一個interface的話,這樣被迫class都要實作每一個技能,但並不是每個class都須要實作每個技能。所以我們把整體結構改成下圖:

可以發現,遵守ISP原則後,JuniorEngineer不再強迫要實作prepareSlides的function,他只需要做好TechSkill內的function即可。

現在我們理解在一個interface內不需要將所有的功能都包在其中,應該挑出對應的需求放入,減低interface肥大的問題,也不需要煩惱class實作不需要的function問題,減少class間的耦合性。

SRP與ISP的差異

看完這SRP與IRP兩篇的人可能會覺得,SRP跟IRP不都是拆分interface嗎?那有什麼不同?

SRP的目的在於一個模組只能有承擔一個責任。
ISP的目的在於不強迫實作的類別實作不需要的function。

我們可以用不同的角度去看這件事。

SRP注重的是設計層面,如何劃分功能的歸類,讓程式方便維護及擴充。
ISP則是注重在客戶端層面,認為只需要呈現客戶端所需要的功能即可。
  • 小結


ISP的目標:

1. 不要讓interface包過多的功能。
2. 不應該強迫實作沒有用到的方法。
3. 實現class間的低耦合。
  • 範例程式碼


範例1:SeniorEngineer

範例2:JuniorEngineer

範例3:實作ISP

  • References


  • 設計模式五大基本原則 SOLID
  • 介面隔離原則