Skip to main content
soso01 blog
  1. Posts/

오브젝트 11장 합성과 유연한 설계

·3 mins

서론 #

  • 합성은 전체를 표현하는 객체가 부분을 표현하는 객체를 포함해서 부분 객체의 코드를 재사용한다.
  • 상속에서 부모 클래스와 자식 클래스 사이의 의존성은 컴파일타임에 해결되지만 합성에서 두 객체 사이의 의존성은 런타임에 해결된다.
  • 합성은 구현에 의존하지 않는다.
    • 합성은 내부에 포함되는 객체의 구현이 아닌 퍼블릭 인터페이스에 의존한다.
    • 합성을 이용하면 포함된 객체의 내부 구현이 변경되더라도 영향을 최소화할 수 있기 때문에 변경에 더 안정적인 코드를 얻을 수 있다.

01. 상속을 합성으로 변경하기 #

  • 10장에서 살펴본 세 가지 문제점을 합성으로 해결하자.

불필요한 인터페이스 상속 문제 #

public class Stack<E> {
	private Vector<E> element = 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);
	}
}
  • 위와 같이 상속 대신 Stack과 Vector의 관계를 합성으로 변경함으로써 퍼블릭 인터페이스의 오염을 막을 수 있다. (add 와 같은 메서드는 상속받지 않는다)

메서드 오버라이딩의 오작용 문제 #

  • 자식 클래스에서 메서드를 오버라이딩했을 때 부모의 메서드에서 오버라이딩된 메서드를 사용하게 되어 사이드 이펙트가 발생할 수 있음.
  • 합성에선 부모의 구현에 영향을 주지 않고 노출한 인터페이스만 사용하기 때문에 구현 결합도를 제거할 수 있다.
  • 기존 클래스의 인터페이스를 그대로 외부에 제공하면서 구현에 대한 결합 없이 일부 작동 방식을 변경하고 싶을 때 포워딩 기법을 사용한다.

부모 클래스와 자식 클래스의 동시 수정 문제 #

  • 합성으로 해결할 수는 없지만 그렇다고 하더라도 상속보다는 낫다.
    • 내부 구현을 변경하더라도 파급효과를 합성되는 객체 안으로 캡슐화 할 수 있기 때문에.

02. 상속으로 인한 조합의 폭발적인 증가 #

  • 상속으로 인해 결합도가 높아지면 코드를 수정하는 데 필요한 작업의 양이 과도하게 늘어나는 경향이 있다.

  • 일반적으로 다음과 같은 두 가지 문제점이 발생한다.

    • 하나의 기능을 추가하거나 수정하기 위해 불필요하게 많은 수의 클래스를 추가하거나 수정해야 한다.
    • 단일 상속만 제공하는 언어에서는 상속으로 인해 오히려 중복 코드의 양이 늘어날 수 있다.
  • 클래스 폭팔

    • 컴파일타임에 결정된 자식 클래스와 부모 클래스 사이의 관계는 변경될 수 없기 때문에 자식 클래스와 부모 클래스의 다양한 조합이 필요한 상황에서 유일한 해결 방법은 조합의 수만큼 새로운 클래스를 추가해야 한다.
    • 기능 a, b, c 를 조합할 수 없고, 상속의 경우 a-b-c, a-c-b, b-a-c, b-c-a, … 모든 경우의 수의 조합을 클래스로 새로 생성해야 하기 때문에 필요이상으로 많은 수의 클래스가 추가된다.

03. 합성 관계로 변경하기 #

  • 상속 관계는 컴파일타임에 결정되고 고정되기 때문에 코드를 실행하는 도중에는 변경할 수 없다.
    • 따라서 여러 기능을 조합해야 하는 설계에 상속을 이용하면 모든 조합 가능한 경우별로 클래스를 추가해야 한다.
    • 합성은 컴파일타임 관계를 런타임 관계로 변경함으로써 이 문제를 해결한다.
    • 합성을 사용하면 구현이 아닌 퍼블릭 인터페이스에 대해서만 의존할 수 있기 때문에 런타임에 객체의 관계를 변경할 수 있다.
  • 예시 생략

객체 합성이 클래스 상속보다 더 좋은 방법이다. #

  • 상속은 부모 클래스의 세부적인 구현에 자식 클래스를 강하게 결합시키기 때문에 코드의 진화를 방해한다.
  • 코드를 재사용하면서도 건전한 결합도를 유지할 수 있는 좋은 방법은 합성을 이용하는 것이다.
    • 단, 여기서 말하는 상속은 구현에 대한 상속이다. 인터페이스 상속에 대해서는 권장하는데 13장에 나옴.

04. 믹스인 #

  • 믹스인은 객체를 생성할 때 코드 일부를 클래스 안에 섞어 넣어 재사용하는 기법을 가리키는 용어다.
    • 상속은 클래스와 클래스 사이의 관계를 고정시키는 데 비해 믹스인은 유연하게 관계를 재구성할 수 있다.
    • 믹스인은 코드 재사용에 특화된 방법이면서도 상속과 같은 결합도 문제를 초래하지 않는다.
  • 스칼라의 트레이트 예제가 나옴