# 8장 의존성 관리하기

잘 설계된 객체지향 애플리케이션은 **작고 응집도 높은 객체**들로 구성된다. 작고 응집도 높은 객체란 책임의 초점이 명확하고 **한 가지 일만 잘하는 객체**를 의미한다.

협력을 위해서는 의존성이 필요하지만 **과도한 의존성은 애플리케이션을 수정하기 어렵게 만든다.** 객체지향 설계의 핵심은 협력을 위해 필요한 의존성은 유지하면서도 변경을 방해하는 의존성은 제거하는데 있다.

## 의존성 이해하기

### 변경과 의존성

어떤 객체가 협력하기 위해 다른 객체를 필요로 할때 두 객체 사이에 **의존성**이 존재하게 된다. 의존성은 **실행 시점**과 **구현 시점**에 서로 다른 의미를 가진다.

의존성은 전이될 수 있기 때문에 의존성의 종류를 **직접 의존성**과 **간접 의존성**으로 나누기도 한다. 직접 의존성이란 말 그대로 한 요소가 다른 요소에 직접 의존하는 경우를 가리킨다. 간접 의존성이란 직접적인 관계는 존재하지 않지만 의존성 전이에 의해 영향이 전파되는 경우를 가리킨다.

```java
// 직접 의존성
Class Movie {
    private AmountDiscountPolicy amountDiscountPolicy 
        = new AmountDiscountPolicy();
    ...
}

// 간접 의존성
class Movie {
    private DiscountPolicy discountPolicy;
    
    Movie(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
    ...
}
```

### 컨텍스트 독립성

클래스는 자신과 협력할 객체의 **구체적인 클래스**에 대해 알아서는 안된다. 구체적인 클래스를 알면 알수록 그 클래스가 사용되는 **특정한 문맥에 강하게 결합**되기 때문이다.

클래스가 사용될 특정한 문맥에 대해 최소한의 가정만으로 이뤄져 있다면 다른 문맥에서 재사용하기가 더 수월해진다. 이를 **컨텍스트 독립성**이라고 부른다.

시스템을 구성하는 객체가 컨텍스트 독립적이라면 해당 시스템은 변경하기 쉽다. 여기서 컨텍스트 독립적이라는 말은 각 객체가 해당 객체를 실행하는 시스템에 관해 아무것도 알지 못한다는 의미다.

## 유연한 설계

### 의존성과 결합도

다른 환경에서 **재사용**하기 위해 내부 구현을 변경하게 만드는 모든 의존성은 바람직하지 않은 의존성이다. 이를 다른 용어로 **결합도**로 일컫는다. 의존성이 바람직할 때 **느슨한 결합도** 또는 **약한 결합도**를 가진다고 말한다. 반대로 두 요소 사이의 의존성이 바람직하지 못할 때 **단단한 결합도** 또는 **강한 결합도**를 가진다고 말한다.

### 자식이 결합을 낳는다

결합도의 정도는 한 요소가 자신이 의존하고 있는 다른 요소에 대해 알고 있는 **정보의 양으로 결정**된다. 한 요소가 다른 요소에 대해 **더 많은 정보를 알고 있을수록 두 요소는 강하게 결합된다.** 서로에 대해 알고 있는 지식의 양이 결합도를 결정한다.

결합도를 느슨하게 만들기 위해서는 협력하는 대상에 대해 필요한 정보 외에는 **최대한 감추는 것**이 중요하다. 그것이 바로 **추상화**다.

### 추상화에 의존하라

추상화란 어떤 양상, 세부사항, 구조를 좀 더 명확하게 이해하기 위해 특정 절차나 물체를 의도적으로 생략하거나 감춤으로써 **복잡도**를 극복하는 방법이다.

일반적으로 추상화와 결합도의 관점에서 의존 대상을 다음과 같이 구분하는 것이 유용하다. 목록에서 아래쪽으로 갈수록 클라이언트가 알아야 하는 지식의 양이 적어지기 때문에 결합도가 느슨해진다.

* 구체 클래스 의존성 -> 추상 클래스 의존성 -> 인터페이스 의존성

### new는 해롭다

결합도 측면에서 new가 해로운 이유는 크게 두 가지다.

* new 연산자를 사용하기 위해서는 **구체 클래스의 이름을 직접 기술**해야 한다. 따라서 new를 사용하는 클라이언트는 추상화가 아닌 구체 클래스에 의존할 수밖에 없기 때문에 결합도가 높아진다.
* **new 연산자는 생성하려는 구체 클래스뿐만 아니라 어떤 인자를 이용해 클래스의 생성자를 호출해야 하는지도 알아야 한다.** 따라서 new를 사용하면 클라이언트가 알아야 하는 **지식의 양**이 늘어나기 때문에 결합도가 높아진다.

훌륭한 객체지향 설계란 객체가 **어떻게 하는지**를 표현하는 것이 아니라 **객체들의 조합**을 선언적으로 표현함으로써 객체들이 무엇을 하는지를 표현하는 설계다.
