아래와 같이
Collection
을 사용할 때 변수와 인스턴스 생성의 타입을 다르게 만드는 이유는 무엇인지 궁금했다. 검색을 통해 학습하고, 간단히 정리했다.
list<> 변수명 = new ArrayList<>();
Map 변수명 = new HashMap();
위와 같이 Collection을 다형성 구조를 사용하는 이유는 2가지다.
1. 개발자의 의도를 명확히 표현한다.
2. 나중에 다른 타입의 자식 객체로 교체하여 사용할 수 있다. 유지보수에 유리하다.
참고 이미지: Collection과 Map의 상속 구조
인터페이스를 설계할 때 메소드의 특징만으로 개발자의 의도를 드러내면 좋다. 이름
, 리턴 타입
, 매개변수
, 예외 선언
만으로 메소드의 기능을 표현할 수 있어야 한다. 예를 들어 List<Member> getMembers()
메소드가 있다고 가정해보자. 이름과 반환 타입만으로 'Member 객체의 묶음을 반환한다'는 의도를 알 수 있다. 또한 개발자가 List 타입을 사용함으로써, '특정한 조건으로 순서가 정렬된 컬렉션을 의도'했다는 것을 알 수 있다.
만약 ArrayList<Member> getMembers()
라는 이름으로 메서드를 만들었다면 어떨까? ArrayList
는 Array
를 기반으로 하는 List
구현체 중 하나에 불과하다. 제품 목록을 가져오는데 반드시 배열의 형태로 가져와야 하는 경우는 드물다. 따라서 '요구 조건에 반드시 ArrayList를 사용하는 것이 포함되어 있지 않다면, ArrayList는 불필요한 제약에 해당'한다. 제품 목록을 전달하고자 하는 개발자의 의도를 명확하게 반영하고 있다고 볼 수 없다.
반환형에 해당하는 변수 타입을 ArrayList
와 같은 상속 구현체로 제한하면 이후 List
를 상속하는 다른 구현체로 교체하는 것이 어려워진다. 반면 반환형을 상위 인터페이스인 List
로 정의하면 구현체 교체가 쉬워진다. 이는 유지보수 생산성이 높아지는 장점이 있다.
상위 인터페이스는 목적에 가깝고, 구현체는 도구에 가깝다. 이는 마치 HTML에서 선택
이라는 목적
을 명시하기 위해 Input
클래스를 만드는 것과 같다. 지금은 단일 선택 기능
이 필요하여 Radio Button
을 도구로 사용하지만, 이후 복수의 선택
을 받아야 한다면 CheckBox
로 도구를 교체하여 사용하는 것이다. 마찬가지로 유지보수 측면에서 상황에 따라 다른 List 구현체로 교체해야 할 가능성이 존재한다면 변수의 타입을 모든 구현체 사용이 가능한 상위 인터페이스 List를 사용하는 것이다.