티스토리 뷰

계승은 코드 재사용을 돕는 강력한 도구지만, 항상 최선이라고는 할 수 없다. 계승은 상위 클래스와 하위 클래스 구현을 같은 프로그래머가 통제하는 단일 패키지 안에서 사용하면 안전하다. 이번 절에서 다루는 문제는 '인터페이스 계승' 에는 적용되지 않는다. 어떤 클래스가 다른 인터페이스를 'implement' 하거나, 어떤 인터페이스가 다른 인터페이스를 'extends' 하는 경우에는 해당되지 않는다.

메서드 호출과 달리, 계승은 캡슐화(encapsulation) 원칙을 위반한다. 상위 클래스의 구현은 릴리즈가 거듭될수록 변경되는데 하위 클래스는 수정된 적이 없어도 망가질 수 있다.


public class InstrumentedHashSet<E> extends HashSet<e> {
	private int addCount = 0;
	public InstrumentedHashSet() {
	}
	
	public InstrumentedHashSet(int initCap, float loadFactor) {
		super(initCap, loadFactor);
	}
	
	@Override
	public boolean add(E e) {
		addCount++;
		return super.add(e);
	}
	
	@Override
	public boolean addAll(Collection<? extends E> c) {
		addCount += c.size();
		return super.addAll(e);
	}
	
	public getAddCount() {
		return addCount;
	}
}

위 코드는 잘못된 계승 사용 사례이다. HashSet 클래스를 계승하여 요소를 추가할 때마다 count를 증가하는 단순한 코드이다. addAll()을 사용하여 요소 3개를 추가했다고 가정하자. 그리고 getAddCount()를 통해서 값을 받으면 몇이 반환될까? 당연히 3을 기대하겠지만, 결과적으로는 6이 나온다. extends 한 HashSet의 경우 addAll을 호출하면 내부적으로 add()를 호출해서 처리하고 있기 때문이다. 따라서 addAll()만을 사용했지만 추가적으로 add()가 3번 호출되는 것이다.


public class ForwardingSet<E> implements Set<E> {
	private final Set<E> s;
	public ForwardingSet(<Set<e> s) {
		this.s = s;
	}
	
	public void add() {
		s.add();
	}
	public void addAll() {
		s.addAll();
	}
	...
	@Override
	public String toString() {
		s.toString();
	}
	@Override
	public boolean equals(Object o) {
		s.equals(o);
	}
	@Override
	public int hashCode() {
		s.hashCode();
	}
}

 

해결방법


forwarding 클래스와 wrapper 클래스를 이용해서 해결할 수 있다. 상위 패턴을 decorator pattern이라고 한다. 상속을 사용하면 각 concrete set마다 기능 추가를 위해 각각 상속해야 하는 반면, decorator 패턴을 이용하면 concrete set을 생성자에 넘김으로 해당 set에 이 기능을 덧붙여 쓸 수 있다.

 

단점


대부분의 문제를 해결할 수 있지만, 한 가지 단점이 있다. 바로 callback frameworks에서 사용될 때이다. 포장된 객체는 포장하는 객체가 누구인지 모르기 때문에, 자기 자신에 대한 참조(this)를 넘기게 되고, callback은 wapper를 거치지 않게 된다. 다시 말하면 생성은 하위 객체로 되어있지만 callback에 this를 넘길 때에는 상위 객체가 하위 객체의 존재를 모르기 때문에 상위 객체의 this가 넘어간다는 의미이다.

 

상속하기 전에 생각해보자.


IS-A 관계일 때 상속을 사용하고 아니면 사용하지 마라. 상속하려는 클래스 API에 어떤 결함은 없는가? 결함이 있다면, 그 결함이 내가 만드는 하위 클래스에 전파되어도 괜찮은 결함인가?

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함