📔
Today Joonas Learned
  • Home
  • About Me
  • Chrome Extension
    • CSS injection
  • Design Pattern
    • SOLID 원칙
      • 1. SRP
      • 2. OCP
      • 3. LSP
      • 4. ISP
      • 5. DIP
    • 생성 패턴
      • Singleton Pattern
      • Abstract Factory Pattern
      • Factory Method Pattern
    • 구조 패턴
      • Adapter Pattern
      • Bridge Pattern
      • Composite Pattern
      • Decorator Pattern
      • Facade Pattern
      • Proxy Pattern
    • 행위 패턴
      • Command Pattern
      • Observer Pattern
      • State Pattern
      • Strategy Pattern
      • Template Method Pattern
  • Graphics
    • OpenGL ES
      • 파이프라인
      • 삼각형 그리기
      • 삼각형 움직이기
      • 다각형 그리기
      • 정사면체 그리기
      • [WIP] 마인크래프트 블럭 만들기
      • [WIP] Lighting, Normal Mapping
  • Internet
    • iOS/Safari
  • Javascript
    • async, defer 속성
    • 나머지 매개변수 (Rest parameter)
    • 화살표 함수 표현 (arrow function expression)
    • Template Literals
    • TDZ (Temporal Dead Zone)
    • Spread syntax (...)
  • Network
    • OSI 7 계층 모델
  • Uncategorized
    • 2021/12/07
    • 2020/09/03
    • 2020/09/04
    • 2020/08/22
  • git/VCS
    • Merge 커밋 메시지 수정
Powered by GitBook
On this page
  • Interface Segregation Principle (ISP; 인터페이스 분리 원칙)
  • 위반 사례
  • 해결
  • 주의 사항
  • 전체 구조 및 코드
  • Links

Was this helpful?

  1. Design Pattern
  2. SOLID 원칙

4. ISP

Interface Segregation Principle (ISP; 인터페이스 분리 원칙)

Previous3. LSPNext5. DIP

Last updated 4 years ago

Was this helpful?

Interface Segregation Principle (ISP; 인터페이스 분리 원칙)

특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.

위반 사례

이 ATM기는 총 3개의 모듈을 가지고 있는데, 어떤 거래(transaction)에 대해서 입금(Deposit), 출금(Withdrawal), 송금(Transfer) 모듈을 각자 만들었다.

각 모듈은 전문화된 기능을 가지기 위해 분리되었지만, 무언가 이상하다.

입금 거래 모듈은 입금만 하면 되는데, 위 구조와 같다면 코드가 이럴것이다.

public class DepositTransaction extends Transaction implements UI {
  @Override public void requestDepositAmount() {
    System.out.println("Request deposit");
  }

  @Override public void requestWithdrawalAmount() {
    throw new UnsupportedMethodException("Can not withdrawal at Deposit Transaction");
  }

  @Override public void requestTransferAmount() {
    throw new UnsupportedMethodException("Can not transfer at Deposit Transaction");
  }

  @Override public void execute() {
    requestDepositAmount();
  }
}
public class WithdrawalTransaction extends Transaction implements UI {
  @Override public void requestDepositAmount() {
    throw new UnsupportedMethodException("Can not deposit at Withdrawal Transaction");
  }

  @Override public void requestWithdrawalAmount() {
    System.out.println("Request withdrawal");
  }

  @Override public void requestTransferAmount() {
    throw new UnsupportedMethodException("Can not transfer at Withdrawal Transaction");
  }

  @Override public void execute() {
    requestWithdrawalAmount();
  }
}
public class TransferTransaction extends Transaction implements UI {
  @Override public void requestDepositAmount() {
    throw new UnsupportedMethodException("Can not deposit at Transfer Transaction");
  }

  @Override public void requestWithdrawalAmount() {
    throw new UnsupportedMethodException("Can not withdrawal at Transfer Transaction");
  }

  @Override public void requestTransferAmount() {
    System.out.println("Request transfer");
  }

  @Override public void execute() {
    requestTransferAmount();
  }
}

입금 거래 모듈을 개발하는 입장에서, 송금이 되지 않는다는 걸 작성하는 일은 필요하지 않고 옳지 못하다.

해결

각 모듈에 맞게 인터페이스를 분리하여 해결할 수 있다.

UI 인터페이스를 모듈별로 분리하였다. 이제 각 모듈은 사용하는 기능들만 구현하면 된다.

먼저, UI 인터페이스를 각 모듈을 위해 쪼개자.

// integrated interface for general
public interface UI extends DepositUI, WithdrawalUI, TransferUI {}

// segregated interface
public interface DepositUI {
    void requestDepositAmount();
}

public interface TransferUI {
    void requestTransferAmount();
}

public interface WithdrawalUI {
    void requestWithdrawalAmount();
}

그리고 각 모듈에서 필요한 인터페이스만 가져다가 구현한다.

public class DepositTransaction extends Transaction {
  private DepositUI depositUI;

  public DepositTransaction(DepositUI ui) {
    depositUI = ui;
  }

  @Override
  public void execute() {
    depositUI.requestDepositAmount();
  }
}
public class WithdrawalTransaction extends Transaction {
  private WithdrawalUI withdrawalUI;

  public WithdrawalTransaction(WithdrawalUI ui) {
    withdrawalUI = ui;
  }

  @Override
  public void execute() {
    withdrawalUI.requestWithdrawalAmount();
  }
}
public class TransferTransaction extends Transaction {
  private TransferUI transferUI;

  public TransferTransaction(TransferUI ui) {
    transferUI = ui;
  }

  @Override
  public void execute() {
    transferUI.requestTransferAmount();
  }
}

이제 필요한 기능만 구현하면 되는 인터페이스가 준비되었다. 그럼 아래와 같은 코딩이 가능하다.

public void testFunction() {
  Transaction custom = new TransferTransaction(new TransferUI() {
    @Override
    public void requestTransferAmount() {
      System.out.println("Request transfer for me");
    }
  });
  custom.execute();
}

주의 사항

개발을 하다보면 클라이언트가 사용하지 않는 메소드를 추가하여, 하나의 인터페이스가 거대해지는 일이 잦다. 쪼개려다보면 애매한 상황도 많고 파일이 많아지는게 또 피곤한 일이라, 굉장히 위배하기 쉬운 원칙이다.

전체 구조 및 코드

위 링크에서 실행 결과와 함께 더 자세히 확인해 볼 수 있다

Links

https://repl.it/@joonasyoon/SOLID-ISP-ATM
https://ko.wikipedia.org/wiki/SOLID_(객체_지향_설계)
http://stg-tud.github.io/sedc/Lecture/ws16-17/3.2-ISP.pdf
https://reflectoring.io/interface-segregation-principle/
The Interface Segregation Principle, Robert C. Martin, C++ Report, June 1996
https://flylib.com/books/en/4.444.1.79/1/