64. 객체는 인터페이스를 사용해 참조하라

주제: 객체는 인터페이스를 사용해 참조하라

  • (개념) 객체를 담는 변수, 필드, 메서드 매개변수, 반환 타입 등을 선언할 때, 실제 객체의 구체 클래스 타입 대신 해당 객체가 구현한 인터페이스 타입을 사용하라는 원칙.

  • (확장) 아이템 51 "매개변수 타입으로 인터페이스 사용" 원칙을 프로그램 전반으로 확장.


핵심 원칙

  • 참조는 인터페이스로 (Reference via Interface)

  • 생성만 클래스로 (Instantiate with Class)

    // 좋은 예: 인터페이스로 참조, 클래스로 생성
    List<User> users = new ArrayList<>();
    Map<String, Data> dataMap = new HashMap<>();
    MemberService service = new MemberServiceImpl();
    
    // 나쁜 예: 구체 클래스로 참조 (유연성 저하)
    ArrayList<User> users2 = new ArrayList<>();

장점

graph LR
  A[Client Code] --> B(Service Interface);
  B -- impl --> C[ServiceImpl_A];
  B -- impl --> D[ServiceImpl_B];
  B -- impl --> E[ServiceImpl_C];
  • 유연성 향상 (Increased Flexibility)

  • 구현 교체 용이 (Easy Implementation Swapping)

  • 테스트 용이성 & DI 활용 (Improved Testability & DI Usage)


주의점 (Potential Issues)

  • 암묵적 동작 의존 (Dependency on Implicit Behavior)

    • LinkedHashSet -> HashSet

  • 컴파일 시점 오류 (Compile-time Errors)


예외

  • 적합한 인터페이스 부재 (No Suitable Interface)

  • 값 클래스 (Value Classes)

    • String, Integer, BigInteger 등. 클래스 타입 직접 사용

  • 클래스 기반 프레임워크 (Class-based Frameworks)

    • java.io.InputStream, OutputStream

  • 구체 클래스 고유 메서드 필수 사용 시 (Need for Class-specific Methods)

    • ArrayList의 TrimToSize()

    • PriorityQueuecomparator()


예외 상황 대처 (Handling Exceptions)

  • Trade-off 인지 (Acknowledge Trade-off) (유연성 < 특정 기능 이점)

  • 대처 방안 (Choose Your Approach)

    1. 구체 클래스 타입 직접 선언 (Declare Concrete Class Type)

    2. instanceof + 캐스팅 (Use instanceof + Casting)


최종 요약 (Key Takeaway)

"특별한 이유(고유 메서드 필수 사용 등)가 없다면, 항상 가장 추상적인 타입(인터페이스 > 상위 클래스)으로 참조하라. 특정 구현의 이점이 유연성보다 명확히 중요할 때만 예외를 고려하라."

Last updated