[Swift] 의존성 주입이란?

Mason Kim·2022년 12월 30일
2

swift

목록 보기
1/7
  • 새싹 동기가 받은 코드리뷰의 메시지에서 영감을 받아 공부 해 보기 시작!
    "이렇게 의존하는 객체들은 생성자를 통해 외부에서 주입해주면 좋을 것 같아요."

🤔 의존성이란 뭘까?

  • 두 객체 간의 연결!
  • 객체 간에 의존 관계가 있다
  • = 한 객체가 바뀔 때 다른 객체에 영향을 준다
  • = 한 객체가 다른 객체를 이용한다

🤔 그럼 의존성 주입이란?

  • Dependency Injection
  • 외부에서 객체를 생성해서 넣어준다! (말 그대로 “주입”한다)
  • 다른 객체를 사용하는 객체 안에서 “직접” 생성해서 쓰는 것이 아니라,
    다른 객체를 "외부에서" 생성해서 사용하는 객체에 넣어주는 것
    - Initializer 에서 넣어줄 수도 있고, (주로 사용)
    - 프로퍼티의 setter 로 넣어줄 수도 있다!

🗣️ 예시를 들어 다른사람에게 설명해보자!

  • “동물 산책시켜주기” 프로그램을 만든다고 가정해보자!
  • 아래 예시는 PetOwner 클래스 안에서 Dog 의 인스턴스를 “직접” 생성해서 사용하고 있다.
    class PetOwner {
        let dog = Dog()
        func walkWithPet() {
            dog.walk()
        }
    }
    
    class Dog {
        func walk() {
            print("개가 걷는다")
        }
    }
    
    let mason = PetOwner()
    mason.walkWithPet()
  • 만약, 클라이언트가 “개가 아닌 고양이도 추가해주세요~” 라고 한다면?
    • 개, 고양이에 대한 경우의 수를 따로 만들어야 하므로
      기존의 PetOwner 를 DogOwner 로 변경하고,
      Cat 을 인스턴스 화 해서 가지는 CatOwner 를 따로 만들어줬다😭

      class DogOwner {
          let dog = Dog()
          func walkWithPet() {
              dog.walk()
          }
      }
      
      class CatOwner {
          let cat = Cat()
          func walkWithPet() {
              cat.walk()
          }
      }
      
      class Cat {
          func walk() {
              print("고양이가 걷는다")
          }
      }
      
      let paul = CatOwner()
      paul.walkWithPet()
  • 그래 그럴 수 있다 치자!
    근데 여기서 만약, 클라이언트가 “패럿, 새, 말.. 이랑도 산책 시키게 해주세요!🤗” 라고 한다면?
    - 각각 ParrotOwner, BirdOwner, HorseOwner 의 클래스를 따로 만들어야 하면 개발자는 미쳐버릴 것이다,,, 이것이 의존성에서 생기는 문제점…
  • 그래서 이를 해결할 수 있는 방법 중 하나가 바로 “의존성주입!”
    protocol Pet {
        func walk()
    }
    
    class Parrot: Pet {
        func walk() {
            print("패럿이 걷는다")
        }
    }
    
    class PetOwner {
        let pet: Pet
    
        // 💉✨의존성주입!✨💉
        init(pet: Pet) {    
            self.pet = pet
        }
        
        func walkWithPet() {
            pet.walk()
        }
    }
    
    let parrot = Parrot()
    let logan = PetOwner(pet: parrot)
    logan.walkWithPet()
    • 여러 타입의 동물들을 묶은 Pet 이라는 프로토콜을 정의하고,
      PetOwner를 초기화 할 때 “외부에서 생성된” Pet 타입을 받아서 넣어줬다!

    • 어떤 타입의 동물이라도 해당 Pet 을 채택하고 있다면 PetOwner 내부에서 walk 라는 역할을 수행할 수 있게 된다!

      💡유지보수 측면에서 굉장히 설계가 유연해지고 재사용성이 높아질 수 있다!

😲 또 다른 장점은 없을까?

  • (테스트가 용이하다는 말이 있던데…!)

  • (나도 아직 테스트 코드를 제대로 짜본 적은 없지만) 위 동물산책 프로젝트에서 예시를 들어보자면!

  • 처음 짰던 Dog 를 직접 내부에서 생성하는 PetOwner 라면 PetOwner를 테스트를 할 때마다 Dog 의 동작 로직에 대해서도 신경을 써야 하지만,

  • protocol Pet 을 의존성 주입으로 받는 PetOwner 라면 테스트 할 때 유니콘, 불사조.. 같은 목업객체의 펫을 임의로 넣어줘서 테스트를 진행할 수 있다!

🤿 심화학습 - 의존 관계 역전 법칙 (DIP) 는 뭘까?

  • 객체지향 설계 SOLID 원칙의 “D” 에 해당하는
    Dependency Inversion Principle! (말이 참 어려워 보인다)
  • “구체적인 객체는 추상화된 객체에 의존해야 한다”
    • 위의 프로젝트를 예시로 들면, 구체적인 객체인 PetOwner 클래스는 추상화한 Pet 프로토콜에 의존해야 한다는 것!

    • 그렇게 함으로서, PetOwner 객체와 Dog, Cat… 객체는 사실상 독립적인 객체가 되는 것!
      양쪽 중에 한 쪽을 수정해야 하더라도 다른 쪽의 객체도 수정해야 하는 문제를 방지할 수 있음!

      😲 나의 느낌으로는, 객체의 독립성을 유지시킬 수 있게 프로토콜이라는 추상화된 징검다리를 놓아준 느낌… 으로 받아들여진다!

profile
iOS developer

0개의 댓글