[이펙티브 자바] 상속 보다는 컴포지션을 사용할 것

Dev. 로티·2022년 2월 3일
1

자바

목록 보기
9/9
post-thumbnail

그동안 코드 재사용을 목적으로 상속 기법을 사용하는 경우가 종종 있었는데 이펙티브 자바를 공부하며 새로운 깨달음을 얻게 되었습니다.

이펙티브 자바에서 제시하는 상속에 관한 내용을 여러분들과 공유하고 싶어 이렇게 포스팅하게되었습니다 ^^


“같은 패키지에서 관리하는 클래스라면 상속도 안전한 방법이다.”
“상속은 객체지향에서 추구하는 캡슐화를 위반할 수 있는 위험성을 갖고 있다.”

저는 그동안 외부 패키지의 클래스를 상속받는 방식으로 프로그래밍을 진행해왔었는데, 문뜩 이런 생각이 들더군요…


“상속으로 인해 외부 패키지에 너무 의존성이 강하게 맺혀있는게 아닌가? 외부 패키지에 있는 클래스가 변경될 경우 그 클래스를 상속받은 모든 클래스가 영향을 받는구나…”

만약 정말 그 클래스를 정말 상속해도 되는 관계 is-a 의 관계라면 크게 문제는 없을 것이라 판단하지만,

그렇지 않을 경우 나중에 코드 관리하는 측면에 있어 굉장히 까다로울 것이라는 생각이 들어 앞으로는 이펙티브자바에서 제시한 컴포지션을 적극적으로 활용해볼 계획입니다 ^^


컴포지션(Composition)

상속으로 인해 발생할 수 있는 강결합 및 캡슐화를 위반할 수 있는 문제를 해결하기 위한 방법입니다.

기존 클래스를 확장하는 대신에 새로운 클래스를 생성하고 이를 private 속성으로 기존 클래스를 갖는 방식입니다.

# 기존 Set 인터페이스를 구현

public class ForwardingSet<E> implements Set<E> {
	private final Set<E> set;
	public ForwardingSet(final Set<E> set){
		this.set = set;
	}
	
	public void clear(){set.clear();}
	public boolean contains(Object o){return set.contains(o);}
	…
	…
	public boolean add(E e){return set.add(e);}
	public boolean addAll(Collection<? extends E> collection){return set.addAll(collection);}
	…
	…
}



# 기존 Set 인터페이스를 구현한 ForwardingSet 클래스를 확장

public class InstrumentedSet<E> extends ForwardingSet<E> {
	private int addCount = 0;
	public InstrumentedSet(final Set<E> set){
		super(set);
	}

	public boolean add(E e){
		addCount++;
		return super.add(e);
	}
	
	public boolean addAll(Collection<? extends E> collection){
		addCount += collection.size();
		return super.addAll(collection);
	}
	
	…
	…
}

0개의 댓글