Dependency Inversion Principle(DIP)(2)

domb
5 min readDec 6, 2023

--

의존성 역전 법칙(2) — 제어의 역전, 의존성 역전

2. 의존성 역전 법칙(DIP)

제어의 역전(Inversion of Control)

제어의 역전을 설명하기 전 DIP(1)에서 사용했던 코드를 가지고 제어의 역전이 없는 경우를 먼저 보겠습니다.

class Parent: Person {
...

func call(_ person: Child) -> String {
child.reply()
}
}

class Child: Person {
...

func reply() -> String {
return "네"
}
}

let parent = Parent()
let child = Child()

parent.call(child) // 네

이 코드를 보실 때 이상한 점이 있진 않았나요??
Parent가 Child에 의존하고 있으며, 제어권(control)은 주체는 Child입니다. 현실이라면 그럴 수도 있겠지만?… 만약에 Child가 아니라 Son이나 daughter로 변경된다면?? 당연하게도 Parent의 call 내부 코드 수정이 필요하고 만약 Parent가 아니라 복잡하고 많은 함수들로 이루어진 객체라면 수정이 쉽진 않을 것입니다.

자 그러면 Parent는 그대로 call()을 통해 아이들을 부르면되고, child에 의존하지 않도록 제어의 주체를 다른 객체로 역전시켜보면 어떨까요??

🔥 중간 개체인 Replyable 프로토콜을 만들어 봅시다.

// 추가
protocol Replyable {
func reply() -> String
}

extension Child: Replyable {}

class Son: Replyable {
func reply() -> String {
"Hello"
}
}
class Daughter: Replyable {
func reply() -> String {
"World"
}
}

// 수정

class Parent: Person {
...

func call(_ person: Replyable) -> String {
person.reply()
}
}

let parent = Parent()
parent.call(Child()) // 네
parent.call(Son()) // Hello
parent.call(Daughter()) // World

자 이제 Parent는 Replyable 을 의존하고 있으며 ChildReplyable에의존하고 있습니다. 기존에는 Child가 제어의 주체였다면 지금은 Parent -> Replyable <- Child가 되어 제어의 역전이 일어났습니다. Child에서 변경이 있다고 해서 Parent의 기존코드가 수정되어야할까요??
당연히 아니겠죠!
이것이 프로그래밍 제어의 주체를 역전시키는 이유이고 인터페이스(protocol)를 사용하는 제어의 역전을 구현하는 하나의 방법입니다.

의존성 역전(Dependency Inversion)

제어의 역전까지 잘 이해했는데 의존성 역전이라는 것은 무엇일까요? 사실 저희는 의존성 역전을 먼저 했다고 해도 과언이 아닙니다.

기존에 A가 B를 의존하고 있던 코드에서 A가 A`를 의존할 수 있도록 변경하고 B가 A`를 의존하게끔 만들어 의존성을 역전시켰습니다. 그럼으로써 프로그래밍 제어의 주체를 역전한 것이죠!

순서도 역전시켜버렸네요… 네.

장단점

우선 의존성 역전을 구현하면서 발생하는 단점은 코드가 좀 더 복잡해질 수 있고 객체가 늘어나 이해하기 어려운 코드가 될 수 있다는 것입니다. 하지만 아래와 같은 상호의존 관계가 많이 발생하게 된다면?.. 서로가 강한 의존관계에 놓이게 되고 A를 수정하기 위해 B를 수정해야하고, B를 수정하기 위해 다시 A를 수정하는 등 개발자는 더 힘들어지겠죠..

let parent = Parent()
let child = Child()

extension Child {
func talk(with parent: Parent) -> String {
parent.call(self)
}
}

parent.call(child)
child.talk(with: parent)

이러한 부분을 생각하지 않고 개발을 한다면 구현은 편리하지만 유연하지 않은 코드가 되고 단일 모듈, 단일 객체의 수정이 어렵고 유지보수 비용이 점차 증가하게될 것입니다.

다음으로는 좀 더 범위를 확장시켜서 아키텍처에서 의존성 역전을 활용할 수 있는 부분을 살펴보겠습니다.

--

--