객체는 클래스가 아닌 인터페이스로 참조하라
클래스가 아닌 인터페이스로 참조하는 예시
• 적합한 인터페이스가 있다면 객체를 클래스 타입이 아닌 인터페이스 타입으로 선언하는 것이 좋다.
◦ 이렇게 되면 구체적인 클래스 타입은 객체를 생성할 때 생성자에서만 사용하면 된다
◦ 아래는 Set 인터페이스를 구현한 LinkedHashSet 변수를 선언하는 코드이다.
코드의 유연성을 높이는 설계
• 기존에 사용하던 구현 클래스 타입을 다른 것으로 바꿔야 하는 상황이 종종 있다.
◦ 더 성능이 좋은 클래스 타입을 사용하고 싶은 경우
◦ 더 다양한 신기능을 사용할 수 있는 클래스 타입이 있는 경우
- HashMap 보다 EnumMap 이 속도도 더 빠르고 순회 순서도 키의 순서와 같아 순서 예측이 가능하다.
- EnumMap 은 키가 열거 타입인 경우에만 사용할 수 있다. 이 때 LinkedHashMap 을 사용하면 키 타입과 상관없이
사용할 수 있으면서 순회 순서를 예측할 수 있다.
• 인터페이스 타입으로 객체를 참조했다면 이런 변동사항에 훨씬 유연한 대처가 가능하다.
◦ 구현 클래스를 교체하고 싶다면 다른 클래스의 생성자를 호출해주기만 하면 되기 때문
• Example
◦ LinkedHashSet 대신 HashSet 를 사용하려고 코드를 수정하는 경우
◦ Set 인터페이스를 사용한 경우 우변의 생성자 외 부분은 수정이 필요 없다
◦ LinkedHashSet 클래스를 사용한 경우 좌, 우변 모두 수정이 필요하다.
◦ 그러나 누군가는 이렇게 생각할 수 있다
- 굳이 인터페이스 써야 하나? 그냥 클래스 쓰고 나중에 수정할 때 좌, 우변 다 바꿔주면 되는거 아님?
- 그러나 이 방법은 자칫하면 컴파일 에러가 발생할 수 있다.
- 처음에 객체를 인터페이스로 만들었다면, 메소드를 설계할 때 파라미터로 인터페이스 객체를 받도록 유도할 수 있다.
- 처음에 객체를 클래스 만들었다면, 메소드를 설계할 때 인터페이스가 아닌 클래스 객체를 파라미터로 받게 해버리는 상황이
발생할 수 있다.
- 인터페이스를 사용하면 이후 구체 클래스가 바뀌어도 컴파일 문제가 없으나 클래스를 사용하면 구체 클래스가
바뀔 때 컴파일 문제가 생긴다. (즉 하나가 바뀔 때 수정해야 하는 부분이 더 많아진다 : 유연성 낮음)
- 즉 애초에 변수를 인터페이스 타입으로 선언해 이 문제를 방지하자.
• 주의사항
◦ 기존에 사용하던 구현 클래스 타입을 다른 것으로 바꿀 때 유의사항
◦ 원래의 클래스가 인터페이스 레벌에서는 없는 특별한 기능을 제공했고, 주변 코드가 이 기능에 의존하여 동작하고 있었다면
새로운 클래스도 동일한 기능을 제공해야 코드가 깨지지 않는다.
- LinkedHashSet 는 반복자의 순회 순서를 보장한다. 이를 염두에 두고 코드를 작성한 상황에서 LinkedHashSet 를
HashSet 으로 대체해버리면 연산 오류가 발생할 수 있다.
참조할 만한 인터페이스가 없는 경우
값 클래스 (Value Class)
• 한번 값이 할당 된 이후에 변경되지 않음을 보장해야 하는 경우
◦ 예) String, BigInteger 등의 불변 객체
• 값 클래스가 여러가지로 구현될 수 있음을 염두에 두고 설계하는 일이 거의 없다.
• final 인 경우가 많고 상응하는 인터페이스가 별도로 존재하는 경우가 드물다.
• 값 클래스는 매개변수 / 변수 / 필드 / 반환 타입으로 사용해도 무방하다.
클래스 기반으로 작성된 프레임워크가 제공하는 객체
• OutputStream 등 java.io 패키지의 여러 클래스가 이 부류에 속한다.
인터페이스에는 없는 특별한 메소드를 제공하는 클래스
• PriorityQueue 클래스는 Queue 인터페이스에는 없는 comparator 메서드를 제공한다.
• 클래스 타입을 직접 사용하는 경우, 이런 특별 메서드의 사용은 꼭 필요한게 아니라면 최소화하는 것이 좋다.
◦ 코드의 유연성을 많이 떨어트리기 때문
정리
객체를 표현할 적절한 인터페이스가 있는지 먼저 찾아보자. 인터페이스로 객체를 참조하면 더 유연한 코드를 작성할 수 있기 때문이다.
만약 없다면, 필요한 기능을 제공해주는 범위 내에서 가장 상위 클래스의 타입을 사용하자.
'Java' 카테고리의 다른 글
[Effective Java] ITEM74 : 메서드가 던지는 모든 예외를 문서화하라 (0) | 2022.11.06 |
---|---|
[Effective Java] ITEM69 : 예외는 진짜 예외 상황에만 사용하라 (0) | 2022.09.20 |
[Effective Java] ITEM59 : 라이브러리를 익히고 사용하라 (0) | 2022.09.06 |
[Effective Java] ITEM54 : null 이 아닌, 빈 컬렉션이나 배열을 반환하라 (0) | 2022.08.24 |
[Effective Java] ITEM49 : 매개변수가 유효한지 검사하라 (0) | 2022.08.06 |