요약
•
객체를 참조할 때는 적합한 인터페이스가 있다면 인터페이스 타입으로 참조하자.
객체는 인터페이스 타입으로 참조하기
•
적합한 인터페이스만 있다면 매개변수 뿐만 아니라 반환값, 변수, 필드 전부 인터페이스 타입으로 선언하자.
// 좋은 예
Set<Son> sonSet = new LinkedHashSet<>();
// 나쁜 예
LinkedHashSet<Son> sonSet = new LinkedHashSet<>();
Java
복사
•
위와 같이 인터페이스를 객체의 참조를 받는 타입으로 사용하면, 나중에 구현 클래스를 교체할 때도 새 클래스의 생성자 혹은 정적 팩터리 메서드를 호출하기만 하면 되어 프로그램이 훨씬 유연해진다.
•
예를 들면 HashMap을 참조하던 변수가 있을 때 EnumMap으로 바꾸면 속도가 빨라지고 순회 순서가 키의 순서와 같아진다. 다만 EnumMap은 키가 열거 타입일 때만 사용할 수 있다. 그렇다면 LinkedHashMap을 적용한다면 성능은 비슷하게 유지하고, 순회 순서도 예측할 수 있게 된다.
•
다만 클래스가 인터페이스의 일반 규약 이외의 특별한 기능을 제공하고 해당 기능에 기대어 동작하는 코드가 있다면, 교체하는 새로운 클래스도 같은 기능을 제공해야 한다. 위의 LinkedHashSet을 HashSet으로 구현하게되면 LinkedHashSet에서 순회 순서를 보장하던 기능이 없어져 문제가 생길 수 있다.
클래스 타입으로 클래스 참조하기
•
적합한 인터페이스가 없다면 당연하게도 클래스로 참조해야 한다.
•
적합한 인터페이스가 없다는 의미에 부합하는 종류는 세 가지가 있다.
◦
String과 BigInteger와 같은 값 클래스는 여러 가지로 구현될 수 있다고 생각하고 설계하지 않기 때문에, final인 경우가 많고 인터페이스가 별도로 존재하는 경우가 거의 없다.
◦
프레임워크가 제공하는 클래스 기반으로 작성된 객체들은 특정 구현 클래스보다 추상 클래스인 기반 클래스를 사용해 참조하는 것이 좋다.
◦
특별한 메서드를 제공하는 클래스들은 클래스 타입을 직접 사용할 때 이런 추가 메서드를 꼭 사용해야 하는 경우를 최소화해야하고, 남발해서는 안된다.
•
적합한 인터페이스가 없다면 클래스의 상속 관계 중 필요한 기능을 만족하는 가장 상위(덜 구체적인)의 클래스를 참조 타입으로 사용하자.