인터페이스 분리 원칙(ISP)

박시시·2022년 10월 20일
0

SOLID

목록 보기
4/5

Robert C. Martin은 해당 원칙에 대해 이렇게 말했다.

“Clients should not be forced to depend upon interfaces that they do not use“

즉 인터페이스를 억지로 공통으로 쓰려하는 것 보다 차라리 분리해서 쓰는 것이 낫다. 몇 가지 사례를 봐보자.

Example 1

먼저 OCP 원칙에서 소개했던 예제를 다시 봐보자.

이 예제에서 우리는 기존에 있던 두 가지 Account 타입에 FixedTermDepositAccount를 추가해도 OCP를 어기지 않을 수 있도록 설계했었다.
즉 Account 인터페이스를 두고 각 Account 타입에서 이를 구현했으며, 클라이언트는 인터페이스와 통신하도록 했다.

하지만 한가지 문제가 있다. 바로 FixedTermDepositAccount에서는 withdraw 기능을 제공하면 안된다는 것이다(물론 현실세계에서는 일정기간 지나면 가능하지만 예제에서는 불가능하다 가정하자). 하지만 Account 인터페이스를 구현하는 구현체 중 하나이므로 FixedTermDepositAccount를 구현할 때는 아래와 같이 구현할 수 있다.

public class FixedTermDepositAccount extends Account {
    @Override
    protected void deposit(BigDecimal amount) {
        // Deposit into this account
    }

    @Override
    protected void withdraw(BigDecimal amount) {
        throw new UnsupportedOperationException("Withdrawals are not supported by FixedTermDepositAccount!!");
    }
}

이렇게 FixedTermDepositAccount 일 경우 withdraw 메서드를 호출하면 예외를 일으키면 된다.
하지만 위의 코드는 ICP를 어길 뿐만 아니라 SOLID의 두 가지 원칙을 더 어길 가능성이 크다.

  • ISP 원칙 위반: FixedTermDepositAccount에서 구현할 필요가 없는 withdraw 메서드까지 강제로 구현해야 한다.
  • OCP 원칙 위반: 클라이언트에서 퍼블릭 인터페이스 메서드인 withdraw를 갖다 쓰는데 예외가 터질 가능성이 생겼으므로 이를 대처하기 위해 클라이언트 코드를 수정해야 될 수도 있다.
  • LSP 원칙 위반: 서브타입인 FixedTermDepositAccount가 Account를 완벽히 대체하지 못한다.

이럴 경우에 인터페이스를 분리해서 사용하게 된다면 문제를 해결할 수 있다.

public interface Account {
	void deposit();
}
public interface Withdrawble extends Account {
	void withdraw();
}

Withdrawble 인터페이스를 하나 더 두고 CurrentAccount와 SavingAccount에서는 Withdrawble을 구현하게 하면 문제가 해결된다.

Example 2

이번엔 clean architecture의 예제를 봐보자.


(출처: https://uchanlee.dev/clean-architecture/book/ch10)

User1에서는 op1, User2에서는 op2, User3에서는 op3만 사용한다고 가정해보자.
이때 User1의 소스코드는 op1만을 사용함에도 op2, op3 두 메서드에도 의존하게 된다.
이때 OPS 클래스의 op2 소스코드가 변경되면 User1도 컴파일 후 배포해야 한다.

이는 OPS를 인터페이스 단위로 분리하여 해결할 수 있다.


(출처: https://uchanlee.dev/clean-architecture/book/ch10)

자바의 경우 op2 메서드가 변경되면 이를 사용하는 User2만 재컴파일하면 된다. 이는 자바가 늦은 바인딩이라는 형식을 사용하기 때문이다.

정리

즉 인터페이스 분리 원칙은 클라이언트의 목적에 맞게 인터페이스를 분리해줘야 한다는 것이다. 구현체에서 불필요하게 호출되는 메서드가 있다면, 이 인터페이스를 사용하는 클라이언트에서는 느닷없는 예외를 만난다든지 하는 이슈가 생길 수 있고, Example 1에서 처럼 여러 SOLID 원칙을 위배하는 상황이 발생할 수 있다.

참조

https://www.baeldung.com/java-interface-segregation
https://uchanlee.dev/clean-architecture/book/ch10/
https://mangkyu.tistory.com/194

0개의 댓글