목차

오브젝트; 의존성과 전이

🗓️

  • 작고 응집도 높은 객체란 책임의 초점이 명확하고 한가지 일만 잘 하는 객체를 의미한다.
  • 작은 객체들은 단독으로 수행할 수 있는 작업이 거의 없기 때문에 기능을 구현하기 위해 다른 객체와 협력해야 한다.
  • 그러나 과도한 협력은 다른 객체에 대해 의존하게 된다.
  • 객체지향 설계는 의존성을 관리하는 것이다. 또한 객체가 변화를 받아들일 수 있게 의존성을 정리하는 기술이다.

의존성 이해하기

변경과 의존성

의존성은 실행 시점과 구현 시점에 서로 다른 의미를 가진다.

  • 실행 시점 : 의존하는 객체가 정상적으로 동작하기 위해서는 실행 시에 의존 대상 객체가 반드시 존재해야 한다.
  • 구현 시점 : 의존 대상 객체가 변경될 경우 의존하는 객체도 함께 변경된다.
public class PeriodCondition implements DiscountCondition {
    private DayOfWeek dayOfWeek;
    private LocalTime startTime;
    private LocalTime endTime;

    //...

    public boolean isSatisfiedBy(Screening screening) {
        return dayOfWeek.equals(screening.getWhenScreened().getDayOfWeek()) &&
            startTime.compareTo(screening.getWhenScreened().toLocalTime()) <=0 &&
            endTime.isAfter(screening.getWhenScreened().toLocalTime()) >= 0;
    }
}
  • 실행 시점에 Screening이 존재해야 한다.
  • 두 요소 사이의 의존성은 의존되는 요소가 변경 될 때 의존하는 요소도 함께 변경될 수 있다.
  • 즉, 전파가능성이 있다.

UML과 의존성

UML에 익숙한 사람이라면 여기서 설명하는 내용이 UML에서 정의하는 의존 관계와는 조금 다르다는 것을 눈치 챘을 것이다. UML에서는 두 요소 사이의 관계로 실체화 관계 (realization), 연관 관계 (association), 의존 관계 (dependency), 일반화/특수화 관계 (generalization/specialization), 합성 관계 (composition), 집합 관계 (aggregation) 등을 정의한다.
이번 장에서 다르고 있는 ‘의존성’ 은 UML의 의존 관계와는 다르다. UML은 두 요소 사이에 존재할 수 있는 다양한 관계의 하나로 ‘의존 관계’를 정의한다. 의존성은 두 요소 사이에 변경에 의해 영향을 주고받는 힘의 역학관계가 존재한다는 사실에 초점을 맞춘다. 따라서 UML에 정의된 모든 관계는 의존성이라는 개념을 포함한다.

의존성 전이

의존성 전이 Transitive dependency 가 의미하는 것은 PeriodConditionScreening에 의존하는 경우 PeriodConditonScreening이 의존하는 Movie, LocalDateTime, Customer에 대해서도 자동으로 의존한다는 뜻이다.

  • 직접 의존성 Direct dependency : 한 요소가 다른 요소에 직접 의존하는 경우
  • 간접 의존성 Indirect dependency : 직접적인 관계는 존재하지 않지만 의존성 전이에 의해 영향이 전파되는 경우

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

  • 런타임 의존성 Runtime dependency : 어플리케이션이 실행되는 시점. 객체지향 어플리케이션에서 런타임의 주인공은 객체다.
  • 컴파일 의존성 Compile dependency : 클래스 사이의 의존성.

어떤 클래스의 인스턴스가 다양한 클래스의 인스턴스와 협력하기 위해서는 협력할 인스턴스의 구체적인 클래스를 알아서는 안 된다. 실제로 협력할 객체가 어떤 것인지는 런타임에 해결해야 한다. 클래스가 협력할 객체의 클래스를 명시적으로 드러내고 있다면 다른 클래스의 인스턴스와 협력할 가능성 자체가 없어진다. 따라서 컴파일 타임 구조와 런타임 구조 사이의 거리가 멀면 멀수록 설계가 유연해지고 재사용이 가능해진다.

Context 독립성

  • 컨텍스트 독립성 : 클래스가 특정한 문맥에 강하게 결합될수록 다른 문맥에서 사용하기는 더 어려워진다. 클래스가 사용될 특정 문맥에 대해 최소한의 가정만으로 이루어져 있다면 다른 문맥에서 재사용하기가 더 수월해진다.

의존성 해결하기

의존성 해결 : 컴파일 타임의 의존성을 실행 컨텍스트에 맞는 적절한 런타임 의존성으로 교체하는 것

  • 객체를 생성하는 시점에 생성자를 통해 의존성 해결
  • 객체 생성 후 setter 메서드를 통해 의존성 해결
    • 실행 시점에 의존 대상을 변경할 수 있기 때문에 설계를 유연하게 만들 수 있다.
    • 객체가 생성된 후에 협력에 필요한 의존 대상을 설정하기 때문에 의존 지정 전에는 객체가 불완전해진다.
  • 메서드 실행 시 인자를 이용해 의존성 해결
    • 협력 대상에 지속적으로 의존 관계를 맺을 필요 없이 메서드가 실행되는 동안만 일시적 관계 가능.