Object - 의존성 관리하기

SeungHyuk Shin·2021년 11월 29일
0

Object

목록 보기
8/13
post-thumbnail

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

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


의존성 이해하기

변경과 의존성

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

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

// 직접 의존성
Class Movie {
    private AmountDiscountPolicy amountDiscountPolicy 
        = new AmountDiscountPolicy();
    ...
}
// 간접 의존성
class Movie {
    private DiscountPolicy discountPolicy;
    
    Movie(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
    ...
}

런타임 의존성과 컴파일 타임 의존성

의존성과 관련해서 다뤄야 하는 또 다른 주제는 런타임 의존성과 컴파일 타임 의존성의 차이다. 만약 여기서 사용하는 런타임과 컴파일타임의 의미를 의해할 필요가 있다.

객체지향 애플리케이션에서 런타임의 주인공은 개게다. 따라서 런타임 의존성이 다루는 주제는 객체 사이의 의존성이다. 반면 코드 관점에서 주인공으 클래스다. 따라서 컴파일 타임 의존성이 다루는 주제는 클래스 사이의 의존성이다.

여기서 중요한 것은 런타임 의존성과 컴파일타임 의존성이 다를 수 있다는 것이다. 사실 유연하고 재사용 가능한 코드를 설계하기 위해서는 두 종류의 의존성을 서로 다르게 만들어야 한다.

컨텍스트 독립성

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

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

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


유연한 설계

의존성과 결합도

다른 환경에서 재사용하기 위해 내부 구현을 변경하게 만드는 모든 의존성은 바람직하지 않은 의존성이다. 이를 다른 용어로 결합도로 일컫는다.

의존성이 바람직할 때 느슨한 결합도 또는 약한 결합도를 가진다고 말한다. 반대로 두 요소 사이의 의존성이 바람직하지 못할 때 단단한 결합도 또는 강한 결합도를 가진다고 말한다.

자식이 결합을 낳는다

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

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

추상화에 의존하라

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

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

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

new는 해롭다

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

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

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

0개의 댓글