보다 덜 구체적인 것(추상적인 것)을 타입으로 참조해서 선언해라.

객체는 클래스(구체적인 것)가 아닌 인터페이스(덜 구체적인 것)로 참조해라.

Set<Son> sonSet = new LinkedHashSet<>(); // Good!
LinkedHashSet<Son> sonSet = new LinkedHashSet<>(); // Bad!

인터페이스를 타입으로 사용하는 습관을 길러두면 프로그램이 훨씬 유연해질 것이다. 나중에 구현 클래스(new LinkedHashsSet)를 교체하고자 한다면 밑의 코드처럼 그저 새 클래스의 생성자(new HashSet) 혹은 다른 정적 팩터리를 호출해주기만 하면 된다.

Set<Son> sonSet = new HashSet<>();

단, 주의할 점이 하나 있다. 원래의 클래스가 인터페이스의 일반 규약 이외의 특별한 기능을 제공하며, 주변 코드가 이 기능에 기대어 동작한다면 새로운 클래스도 반드시 같은 기능을 제공해야 한다. 예를 들어, LinkedHashSet이 따르는 순서 정책을 정하고 동작하는 상황에서 이를 HashSet으로 바꾸면 문제가 될 수 있다. HashSet은 반복자의 순회 순서를 보장하지 않기 때문이다.

인터페이스가 없다면 덜 구체적인 클래스로 참조해라.

인터페이스가 없는 클래스도 있을 것이다. 그 때에는 클래스의 계층 구조 중 필요한 기능을 만족하는 가장 덜 구체적인(상위의) 클래스를 타입으로 사용해라.

References