<aside> 💡 상속은 코드를 재사용하는 강력한 수단이지만, 항상 최선은 아니다!
</aside>
상위 클래스와 하위 클래스를 모두 같은 프로그래머가 통제하는 패키지 안이라면 안전하다.
메서드 호출과 달리 상속은 캡슐화를 깨뜨린다.
public class InstrumentedHashSet<E> extends HashSet<E> {
private int addCount = 0;
public InstrumentedHashSet() {
}
public InstrumentedHashSet(final int initCap, final float loadFactor) {
super(initCap, loadFactor);
}
@Override
public boolean add(final E e) {
addCount++;
return super.add(e);
}
@Override
public boolean addAll(final Collection<? extends E> c) {
addCount += c.size();
return super.addAll(c);
}
public int getAddCount() {
return addCount;
}
}
addAll
메서드로 원소 3개를 인스턴스에 더했다고 해보자.InstrumentedHashSet<String> s = new InstrumentedHashSet<>();
s.addAll(List.of("틱", "틱틱", "펑"));
HashSet
의 addAll
은 각 원소를 add
메서드를 호출해 추가하는데, 이 때 불리는 add
는 InstrumentedHashSet
에서 재정의된 메서드이다.addCount
에 값이 중복해서 더해진 것.→ 하위 클래스에서 addAll
메서드를 재정의하지 않거나, 다른 식으로 재정의하면 해결할 수 있다.
private
필드를 써야 한다면 구현 자체가 불가능하다.하위 클래스가 깨지기 쉬운 이유는 또 존재한다.
Hashtable
과 Vector
를 컬렉션 프레임워크에 포함시키자, 관련된 보안 구멍을 다 수정해야 했었다.<aside> 💡 다행히, 이상의 문제들을 모두 피할 수 있다! → 컴포지션(composition : 구성)
</aside>
private
필드로 기존 클래스의 인스턴스를 참조하게 하자.