-
SOLID - ISP (인터페이스 분리 원칙)Clean Architecture 2026. 1. 11. 18:51

안녕하세요~ 오늘은 SOLID 원칙 중 네 번째, 인터페이스 분리 원칙에 대해 알아보겠습니다!
1. 정의
인터페이스 분리 원칙(Interface Segregation Principle)은 클라이언트 자신이 사용하는 기능 단위까지 인터페이스를 작게 분리하는 원칙입니다. 작게 분리하는 이유는, 클라이언트가 자신이 사용하지 않는 메서드에 의존하도록 강제하지 않기 위함인데요. 인터페이스를 적절히 단위로 분리하면 특정 클라이언트가 불필요한 메서드를 구현하는 상황을 방지할 수 있습니다. 이는 결과적으로 클라이언트 코드의 결합도를 낮추고, 시스템의 유연성을 증가시키며 변경 시 영향 범위를 최소화하는 데 도움을 줍니다.
2. 코틀린 위반/준수 예제
// ISP 위반 interface Worker { fun work() fun eat() } class Human: Worker { override fun work() { println("Human can work") } override fun eat() { println("Human can eat") } } class Robot: Worker { override fun work() { println("Robot can work") } override fun eat() { throw UnsupportedOperationException("Robot can't eat") } }코틀린 예제를 살펴보겠습니다. 위 코드에서 Worker 인터페이스는 work()와 eat() 이라는 두 개의 메소드를 정의하고 있습니다. 실제로 사람은 일을 하고 밥도 먹으니 이 인터페이스를 구현하는 데 아무런 문제가 없습니다. 하지만 로봇은 어떨까요? 로봇은 일은 할 수 있지만 음식을 먹지는 못합니다. 이 상황에서 Robot 클래스는 자신에게 필요 없는 eat() 메서드를 억지로 상속받게 되고, 해당 기능을 수행할 수 없어 예외를 던지고 있습니다. 특정 클라이언트(Robot)가 자신이 사용하지 않는 메서드에 불필요하게 의존하고 있기 때문에 이는 ISP 원칙을 위반합니다.
// ISP 준수 interface Workable { fun work() } interface Eatable { fun eat() } class Human: Workable, Eatable { override fun work() { println("Human can work") } override fun eat() { println("Human can eat") } } class Robot: Workable { override fun work() { println("Robot can work") } }앞서 발생했던 문제를 해결하기 위해, Worker 인터페이스를 Workable과 Eatable 이라는 두 개의 인터페이스로 분리했습니다. 이때, Human 클래스는 두 인터페이스를 모두 구현하면 됩니다. Robot 클래스는 이제 본연의 기능인 Workable만 구현하여, 더 이상 예외를 던지는 코드를 작성할 필요가 없습니다. 클라이언트는 자신이 사용하지 않는 메서드에 더이상 의존하지 않아 ISP 원칙을 준수할 수 있게 되었습니다.
3. 안드로이드 위반/준수 예제
// ISP 위반 interface ItemTouchListener { fun onClick() fun onLongClick() fun onSwipe() } class HomeFragment: ItemTouchListener { override fun onClick() { // 클릭 기능 처리 } override fun onLongClick() { // 사용 X } override fun onSwipe() { // 사용 X } }이번에는 안드로이드에서 흔히 발생하는 사례를 살펴보겠습니다. 여기 클릭, 롱 클릭, 스와이프 이벤트를 모두 처리하는 ItemTouchListener 인터페이스가 있습니다. 만약 HomeFragment 에서 단순 클릭 이벤트만 필요하다면 어떻게 될까요? 위 코드에서 사용하지 않는 onLongClick()과 onSwipe() 메소드를 억지로 구현하여 의도적으로 비워둬야 합니다. 이런 설계는 인터페이스에 작은 변경이 생겨도 해당 기능을 쓰지 않는 모든 클래스에 영향을 주어 유지보수를 더 어렵게 만듭니다.
// ISP 준수 interface Clickable { fun onClick() } interface LongClickable { fun onLongClick() } interface Swipeable { fun onSwipe() } class HomeFragment: Clickable { override fun onClick() { // 클릭 처리 } }기존 인터페이스를 Clickable, LongClickable, Swipeable로 각각 세분화했습니다. 이렇게 기능을 독립적인 인터페이스로 분리하면 명확하게 의도를 전달할 수 있고, 더 이상 사용하지 않는 기능을 위해 빈 본문을 만들거나 예외 처리를 하지 않게 되어 코드 가독성이 좋아집니다. 나중에 스와이프 기능이 필요한 새로운 화면이 생기면 Swipeable 인터페이스만 구현하면 되기에, 재사용성 또한 좋아집니다.
4. 클린 아키텍처와의 연관성
인터페이스 분리 원칙을 설계해서 작성하면, 클린 아키텍처의 각 레이어는 자신이 필요한 기능만을 제공하는 인터페이스에 의존하게 됩니다. 이는 코드 변경의 범위를 줄이고 유지보수를 쉽게 만들어줍니다. 또한, 인터페이스 분리 원칙은 한개의 클래스가 하나의 책임만을 갖는 단일 책임 원칙과 유사한 맥락을 지닌다고 볼 수 있습니다.
오늘은 인터페이스 분리 원칙에 대해 살펴보았습니다. 다음 시간에는 SOLID 원칙의 마지막 다섯 번째 원칙, 의존성 역전 원칙에 대해 알아보겠습니다!
'Clean Architecture' 카테고리의 다른 글
SOLID - LSP (리스코프 치환 원칙) (0) 2025.12.14 SOLID - OCP (개방 폐쇄 원칙) (0) 2025.11.30 SOLID - SRP (단일 책임 원칙) (0) 2025.10.05 UI 레이어란? (3) 2025.08.24 Presentation 레이어란? (8) 2025.08.17