상속
합성
<aside> 💡
코드 재사용을 위해서는 객체 합성이 클래스 상속보다 더 좋은 방법이다
</aside>
불필요한 인터페이스 상속 문제
메서드 오버라이딩의 오작용 문제
부모 클래스와 자식 클래스의 동시 수정 문제
부모 - 자식 간 개념적 결합으로 인해 부모 클래스를 변경할 때 자식 클래스도 함께 변경
상속을 합성으로 바꾸는 방법: 자식 클래스에 선언된 상속 관계를 제거하고 부모 클래스의 인스턴스를 자식 클래스의 인스턴스 변수로 선언
public class Properties {
private Hashtable<String, String> properties = new Hashtable<>();
public String setProperty(String key, String value) {
return properties.put(key, value);
}
public String getProperty(String key) {
return properties.get(key);
}
}
public class Stack<E> {
private Vector<E> elements = new Vector<>();
public E push(E item) {
elements.addElement(item);
return item;
}
public E pop() {
if (elements.isEmpty()) {
throw new EmptyStackException();
}
return elements.remove(elements.size() - 1);
}
}
public class InstrumentedHashSet<E> : implements Set<E> {
private int addCount = 0;
private Set<E> set;
public InstrumentedHashSet(Set<E> set) {
this.set = set;
}
@Override
public boolean add(E e) {
addCount++;
return set.add(e);
}
@Override
public boolean addAll(Collection<? extends E> c) {
addCount += c.size();
return set.addAll(c);
}
public int getAddCount() {
return addCount;
}
©Override public boolean remove(Object o) { return set.remove(o); }
©Override public void clear() { set.clear(); }
©Override public boolean equals(Object o) { return set.equals(o); }
©Override public int hashCode() { return set.hashCode(); }
©Override public Spliterator<E> spliterator() { return set.spliterator(); }
©Override public int size() { return set.size(); }
©Override public boolean isEmpty() { return set.isEmpty(); }
©Override public boolean contains(Object o) { return set.contains(o); }
©Override public Iterator<E> iterator() { return set.iterator(); }
©Override public Object[] toArray() { return set.toArray(); }
©Override public <T> T[] toArray(T[] a) { return set.toArray(a); }
©Override public boolean containsAll(Collection<?> c) { return set.containsAll(c); }
©Override public boolean retainAll(Collection<?> c) { return set.retainAll(c); }
©Override public boolean removeAll(Collection<?> c) { return set.removeAll(c); }
}
class PersonalPlaylist
{
public:
PersonalPlaylist()
: playlist(nullptr)
{
playlist = new Playlist();
}
~PersonalPlaylist() {}
void Emplace(const Song& song) const
{
playlist->Emplace(song);
}
void Erase(const Song& song) const
{
std::erase(playlist->GetTracks(), song);
playlist->GetSingers().erase(song.GetSinger());
}
private:
Playlist* playlist;
};


기본 정책의 계산 결과에 적용된다
선택적으로 적용할 수 있다
조합 가능하다
부가 정책은 임의의 순서로 적용 가능하다