카테고리:

업데이트:

1. 들어가기

이번 포스트는 코드를 유연하게 만드는 방법에 대해 알아보겠습니다.

2. 코드를 유연하게 만드는 방법

다음과 같이 구현 클래스를 타입으로 선언하면 어떤 문제가 있을까요?

   HashSet<String> map = new HashSet<>();

이 코드는 컴파일 오류가 발생하지도, 프로그램 로직 상 문제가 있는 코드도 아닙니다.

하지만, 이렇게 작성을 하게 되면 프로그램이 유연하지 못합니다.

만약 개발자가 LinkedHashSet을 사용하다가 HashSet으로 바꾼다고 가정해봅시다.

그럼 전체를 다음과 같이 변경해야 합니다.

   // 변경 전
   LinkedHashSet<String> map = new LinkedHashSet<>();

   // 변경 후
   HashSet<String> map = new HashSet<>();

하지만, 애초에 다음과 같이 작성했다면 어떨까요?

   // 변경 전
   Set<String> map = new LinkedHashSet<>();

   // 변경 후
   Set<String> map = new HashSet<>();

앞 선언 부분은 그대로 놔둔 채 구현 클래스만 바꿔주면 되는 장점이 있습니다.

3. 주의해야할 점

편한 부분도 있지만 주의해야할 점이 하나 있습니다.

기존 클래스가 인터페이스 일반 규약 이외 특별한 기능을 제공하는 경우에는

클라이언트에서 기존 클래스의 특별한 기능을 사용한다

새로운 클래스도 그 기능을 반드시 제공해야 합니다.

4. 적합한 인터페이스가 없는 경우

경우에 따라서는 적합한 인터페이스가 없는 경우가 없을 수 있습니다.

그럴 경우에는 당연히 클래스로 참조해야 하는데

아래와 같은 세 부류가 있을 수 있습니다.

  1. 값 클래스인 경우

    String이나 BigInteger 같은 값 클래스는 여러 가지로 구현된다고 설계하는 일은 거의 없습니다.

    따라서 final인 경우가 많고 상응하는 인터페이스가 별도로 존재하는 경우가 드뭅니다.

    그래서 이러한 값 클래스는 매개변수, 변수, 필드, 반환 타입으로 사용해도 무방합니다.


  2. 클래스 기반으로 작성된 프레임워크가 제공하는 객체인 경우

    java.io 패키지 내부에는 BufferedOutputStream이나 FileOutputStream 등 여러 클래스가 존재하는데

    이 경우에는 기반 클래스인 OutputStream을 사용할 수 있습니다.


  3. 특별한 메서드를 제공하는 클래스인 경우

    PriorityQueue 클래스는 Queue 인터페이스에는 없는 comparator 메서드를 제공해야 합니다.

    따라서 이러한 클래스를 사용하는 경우에는 해당 클래스 타입을 직접 참조합니다.

5. 정리

이번 포스트에서는 코드를 유연하게 만드는 방법에 대해 알아보았습니다.

대부분의 경우에는 인터페이스를 참조하여 코드를 유연하게 해야 하지만,

적합한 인터페이스가 없거나 특별한 기능을 제공하는 클래스 같은 경우에는

필요한 기능을 만족하는 가장 덜 구체적인 클래스를 타입으로 사용하여 코드를 유연하게 만들어야 합니다.

            
              📕 개인 기록용 블로그입니다.
              😊 오타나 잘못된 정보가 있을 경우 댓글이나 메일로 말씀해주시면 바로 수정하겠습니다! 😊
          

댓글남기기