Study/object

[엘레강트 오브젝트] 3-6장 부 ctor 밖에서는 new를 사용하지 마세요

에디개발자 2021. 9. 26. 07:00
반응형

나를 닮았다고 한다...

이 글은 엘레강트 오브젝트 새로운 관점에서 바라본 객체지향 도서를 보며 스터디한 글입니다.

책에서 주장하는 내용을 정리하였으며 예제들은 모두 코틀린 코드로 변환하여 작성하였습니다.

 

목차

  1. 잘못된 의존성 주입
  2. 올바른 의존성 주입
  3. 정리

1. 잘못된 의존성 주입

잘못된 의존성 주입은 종종 치명적인 결과를 초래합니다. 코드로 살펴보겠습니다.

class Cash(
    private val dollars: Int
) {
    fun euro() = 
        Exchange().rate("USD", "EUR") * this.dollars
}

euro() 메서드 안에서 Excahnge 인스턴스를 생성하고 있습니다. 이 코드의 문제는 '하드코딩된 의존성'입니다. Cash 클래스는 Exchange 클래스에 직업 연결되어 있기 때문에, 의존성을 끊기 위해서는 Cash 클래스의 내부 코드를 변경해야만 합니다.

 

fun test() {
    val five = Cash(5)
    println("$5 equals to ${five.euro()}")
}

이 코드는 의존성 문제가 되는 클래스를 사용하여 테스트 코드를 작성한 것입니다. 만약에 Exchange 객체의 rate() 메서드에서 외부 연동을 진행한다고 하면 테스트 코드를 실행할 때마다 외부와 연동을 진행해야 합니다. 이 경우 외부 연동을 반드시 진행할 수 밖에 없습니다. 

 

2. 올바른 의존성 주입

객체 생성자의 인자로 Exchange를 전달 받아 private 프로퍼티 안에 캡슐화하여 작성해보겠습니다. 

class Cash(
    private val dollars: Int,
    private val exchange: Exchange
) {
    fun euro() =
        this.exchange.rate("USD", "EUR") * this.dollars
}

 

위 코드를 테스트하는 올바른 코드도 작성해보겠습니다.

fun test() {
    val five = Cash(5, FakeExchange())
    println("$5 equals to ${five.euro()}")
}

이처럼 작성한다면 외부통신을 진행하지 않고도 테스트를 진행할 수 있습니다.

 

편의를 위해 부 생성자를 여러개 추가할 수 있습니다.

class Cash(
    private val dollars: Int,
    private val exchange: Exchange
) {
    // 부 생성자
    constructor(): this(0)
    
    // 부 생성자
    constructor(dollars: Int): this(dollars, Exchange())
    
    fun euro() =
        this.exchange.rate("USD", "EUR") * this.dollars
}

이와 같이 작성한다면 주 생성자에서는 Exchange의 의존성을 주입할 수 있고, 부 생성자에서는 new 생성자를 통해 Exchange 의존성을 주입할 수 있습니다. 즉, 우리 스스로가 의존성 주입을 완전히 제어가 가능합니다.

 

3. 정리

객체가 필요한 의존성을 직접 생성하는 것이 아니라 생성자를 통해 의존성을 주입해야합니다.
반응형