joonamin / study

개인 공부 및 스터디 Repo
3 stars 1 forks source link

[아이템13] HashSet 객체를 TreeSet 타입으로 복제할 수 있다. #14

Open rlooo opened 2 years ago

rlooo commented 2 years ago

pg 86. 관례상 모든 범용 컬렉션 구현체는 Collection이나 Map 타입을 받는 생성자를 제공한다. 인터페이스 기반 복사 생성자와 복사 팩터리의 더 정확한 이름은 '변환 생성자'와 '변환 팩터리'다. 이들을 이용하면 클라이언트는 원본의 구현 타입에 얽매이지 않고 복제본의 타입을 직접 선택할 수 있다. 예컨대 HashSet 객체 s를 TreeSet 타입으로 복제할 수 있다.

밑줄 친 부분에 대한 예시나 더 구체적인 설명을 듣고 싶습니다.

joonamin commented 2 years ago

CollectionMap은 인터페이스입니다. 대부분의 자료구조 컨테이너(?)들은 Collection 이나 Map를 상속받아서 내부 연산에 활용합니다.

Map 을 예로 들겠습니다. Map은 [key, value] 쌍을 저장하여 key에 대응하는 value의 값을 가져오기 위하여 사용합니다. Map 은 인터페이스이고 구현체는 대표적으로 HashMapTreeMap이 있습니다.
각각의 장단점은 명확하지만, 어쨌거나 key에 대응하는 value를 가져온다.라는 목적성은 동일한거죠.


설명의 편의성을 위하여 Map의 기능을 활용하는 커스텀 클래스를 정의해보겠습니다.

public class MyCustomDictionary {
    // ... 생략 ...
    private final Map<String, int> dictionary;
    MyCustomDictionary(Map<String, int> dictionary) { this.dictionary = dictionary;}
}

위의 상황에서, 클라이언트는 Map의 구현체를 알지 못하고도 본질적으로 Map의 기능을 활용할 수 있습니다. 이 경우, MyCustomDictionary를 사용하는 클라이언트는 여러 상황을 고려하여 구현체(TreeMap, HashMap) 중 하나를 선택하여 사용할 수 있겠죠?? 유연성을 보장해주는겁니다.

범용 컬렉션 구현체들은 이러한 방식으로 내부 구현을 추상화 시키므로서, 객체 지향적 이점을 취했습니다.


예컨대 HashSet 객체 s를 TreeSet 타입으로 복제할 수 있다.

위 내용을 설명하기 위하여 클래스의 원형을 살펴보겠습니다.

  1. public HashSet(Collection<? extends E> c)
  2. public TreeSet(Collection<? extends E> c)

두 개의 구현 클래스 모두 Collection타입을 인자로 받는 생성자가 존재합니다. Collection 타입의 내부 원소들을 인자로 가지는 HashSet 또는 TreeSet을 구성하기 위해서 사용되는 것이죠. 리스코프 치환 원칙에 따라서 HashSetTreeSet은 Collection 타입으로 치환이 가능합니다. 그렇기 떄문에, HashSet의 생성자의 인자로 TreeSet을 넘겨주어도 된다는 뜻이죠. 그 반대도 물론 가능합니다.