티스토리 뷰

IT/SOLID

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

Stv 2025. 4. 28. 19:47

목차


    1. ISP란?

    "클라이언트는 자신이 사용하지 않는 메서드에 의존하면 안 된다"
    • 즉, 하나의 거대한 인터페이스를 만들어서 모든 기능을 몰아넣지 않는다.
    • 클라이언트(사용자)의 관점에 맞춰 필요한 인터페이스만 제공하라는 원칙이다.

    2. 왜 ISP가 필요한가?

    ❌ Fat Interface(비대한 인터페이스)의 문제

    • 클라이언트가 불필요한 메서드까지 강제로 구현하거나 알게 됨
    • 구현체가 사용하지 않는 기능에 끌려가서 변화에 민감해짐
    • 인터페이스 하나 수정 시, 모든 구현체가 영향받는 변경 전파 문제

    ✅ ISP를 지키면

    • 필요한 기능만 알게 되어 의존성 최소화
    • 변경이 국소화되고, 코드 유지보수가 쉬워짐
    • 인터페이스 별로 역할이 명확해져서 설계가 깔끔해짐

    3. ISP 위반 예시

     

    📌 문제 코드

    public interface Machine {
        void print();
        void scan();
        void fax();
    }
    
    public class Printer implements Machine {
        public void print() { ... }
        public void scan() { throw new UnsupportedOperationException(); }
        public void fax() { throw new UnsupportedOperationException(); }
    }
    • Printer는 프린트 기능만하지만, scan, fax까지 억지로 구현해야 함
    • 수정/확장할 때 쓸데없는 충돌 위험 발생

    4. ISP를 지키는 설계

     

    📌 해결 방법 : 인터페이스 분리

    public interface Printer {
        void print();
    }
    
    public interface Scanner {
        void scan();
    }
    
    public interface Fax {
        void fax();
    }
    public class SimplePrinter implements Printer {
        public void print() { ... }
    }
    
    public class MultiFunctionPrinter implements Printer, Scanner, Fax {
        public void print() { ... }
        public void scan() { ... }
        public void fax() { ... }
    }
    • 필요한 기능만 구현
    • SimplePrinter는 Scanner나 Fax를 몰라도 됨 -> 의존성 최소화

    5. 실무에서 자주 보는 ISP 위반 사례

    위반 예 문제점
    서비스 인터페이스 하나에 CRUD + 복잡한 도메인 기능 모두 몰아넣기 사용자가 불필요한 메서드를 다 알아야 함
    공통 API 인터페이스에 다양한 서비스 기능 포함 확장성, 유지보수성 급격히 하락
    대형 인터페이스에서 일부 기능만 사용 수정 시 영향 범위 과도하게 커짐

     

    6. 실무에서 ISP를 지키는 방법

     

    ✔️ 역할별로 인터페이스 분리

    • 한 인터페이스가 하나의 역할만 당당하게 설계

    ✔️ 인터페이스는 클라이언트 관점에서 설계

    • "내가 제공하고 싶은 기능"이 아니라
    • "사용자가 원하는 기능"에 맞춰 인터페이스를 정의

    ✔️ 여러 인터페이스 구현 허용

    • 하나의 구현체가 여러 작은 인터페이스를 구현하도록 설계
    public interface Savable {
        void save();
    }
    
    public interface Printable {
        void print();
    }

     

    7. ISP를 지키는 설계 패턴

    패턴 설명
    인터페이스 기반 프로그래밍 역할에 따른 작은 인터페이스 설계
    어댑터 패턴(Adapter Pattern) 다양한 인터페이스를 변환하여 클라이언트에 제공
    컴포지션 기반 설계 필요한 인터페이스만 조합하여 사용

     

    ✅ 마무리 요약

    • ISP는 "클라이언트는 자신이 필요하지 않은 메서드에 의존하면 안 된다"는 설계 원칙이다.
    • Fat Interface를 피하고, 작은 역할별 인터페이스로 쪼개야 한다.
    • 클라이언트 중심 관점에서 인터페이스를 설계해야 유지보수가 용이하다.
    • 실무에서는 서비스 인터페이스, API 설계, 모듈화에 필수적으로 적용된다.

    🔜 다음 포스팅에서는 DIP - 의존성 역전 원칙 : "구현이 아닌 추상화에 의존하라"라는 주제를 다뤄볼 예정이다.