의존성 주입이란?

오해성·2020년 8월 18일
3

기술 상점

목록 보기
2/10
post-thumbnail

해당 게시글에서는 의존성 주입이란 무엇인가에 대한 내용과 어떻게 하면 의존성 주입에 대해 잘 활용할 수 있을지에 대해 다룹니다.

이곳의 예제 코드는 TS기반입니다.


🤔 의존성?

의존성 주입에대해 설명하기 전에 우선 의존성이 무엇인지에 대해 설명하겠습니다.
의존성이란 누구한테 "의존" 한다 라는 의미로 혼자서는 해내지 못한다라는 말과 같습니다.

간단한 예시를 들자면 개발자는 노트북을 사용해 개발을 합니다. 여기서 개발자는 노트북이 없으면 개발을 할 수 없기 때문에 개발자는 노트북에 의존성을 띄고 있는 거죠.

코드로 예시를 들자면 다음과 같습니다.

class Laptop {
  public turnOn() { }
}

class Programmer {
  private laptop: Laptop;
  
  constructor() {
    this.laptop = new Laptop();
  }
  
  public programming() {
    this.laptop.turnOn();
  }
}

const programmer: Programmer = new Programmer();
programmer.programming();

😦 대표적 문제점

구성요소가 의존성을 띄면 변경에 민감해 집니다.

위 예제코드에서 Laptop이 아닌 Macbook을 사용하도록 코드를 수정할 경우 다음과 같습니다.

class Laptop {
  public turnOn() { }
}

class Macbook extends Laptop { }

class Programmer {
  private laptop: Laptop;
  
  constructor() {
    this.laptop = new Macbook();
  }
  
  public programming() {
    this.laptop.turnOn();
  }
}

const programmer: Programmer = new Programmer();
programmer.programming();

Mackbook 클래스를 하나 만들어 주고 Programmer 변수인 laptop가 Macbook 객체를 할당받도록 수정해주면 됩니다.

여기서 문제는 Programmer 클래스가 Laptop 클래스를 의존하고 있었기 때문에 Programmer 클래스를 직접 변경 시켜주어야 합니다.

이렇게 의존성의 문제는 하나를 변경하면 거기에 의존하는 다른 것들도 모두 변경해 주어야 한다는 점입니다.

이러한 문제점을 해결할 수 있는것이 바로 "의존성 주입" 입니다.


😀 의존성 주입

의존성 주입이란 말그대로 외부에서 의존성을 주입 해주는 것을 말합니다.

예제를 보시면,

class Laptop {
  public turnOn() { }
}

class Programmer {
  private laptop: Laptop;
  
  constructor(laptop: Laptop) {
    this.laptop = laptop;
  }
  
  public programming() {
    this.laptop.turnOn();
  }
}

const programmer: Programmer = new Programmer(new Laptop);
programmer.programming();

Programmer 클래스가 의존하던 Laptop 클래스의 객체를 외부에서 주입해 주고 있습니다.

이번에는 Programmer가 Macbook을 사용하게 해보겠습니다.

class Laptop {
  public turnOn() { }
}

class Macbook extends Laptop { }

class Programmer {
  private laptop: Laptop;
  
  constructor(laptop: Laptop) {
    this.laptop = laptop;
  }
  
  public programming() {
    this.laptop.turnOn();
  }
}

const programmer: Programmer = new Programmer(new Macbook);
programmer.programming();

이런식으로 의존성 주입을 사용해주면 의존하고 있는 클래스 객체를 직접 수정하지 않고 구현해 줄 수 있습니다.

하지만 이렇게 의존성 주입만 사용하는 것도 문제가 됩니다. 때문에 의존 관계 역전의 원칙에 대해 알아 보겠습니다.


🥱 의존 관계 역전의 원칙

이름만 들어 보면 되게 어려워 보이죠?
의존 관계 역전의 원칙은 SOLID 원칙중 하나로 변화하기 쉬운 것보단 변화하기 어려운 것에 더 의존하라는 원칙입니다.

간단히 예를 들자면 개발자가 개발을 할때 사용하는 기종(Macbook, Gram...) 과 같은 것들은 변하기 쉬운 것 들입니다. 하지만 개발자들이 노트북을 가지고 코딩을 한다는 점은 변하기 어려운 점이죠.

예제를 보시죠

interface Laptop {
  turnOn(): void;
}

class Macbook implements Laptop { 
  public turnOn() { }
}

class Macbook implements Laptop { 
  public turnOn() { }
}

class Programmer {
  private laptop: Laptop;
  
  constructor(laptop: Laptop) {
    this.laptop = laptop;
  }
  
  public programming() {
    this.laptop.turnOn();
  }
}

const programmer: Programmer = new Programmer(new Macbook);
programmer.programming();

const programmer: Programmer = new Programmer(new Gram);
programmer.programming();

위와 같이 Macbook 클래스, Gram 클래스가 Laptop이라는 인터페이스를 구현하고 있습니다.

또 Programmer 클래스를 Laptop 타입의 인자를 받고 있습니다.

여기서 Macbook, Gram과 함께 Samsung 노트북도 사용하고 싶다면 Laptop 인터페이스를 구현하는 Samsung 노트북 클래스를 만들어 Programmer에게 주입 해도 전혀 문제 될 것이 없습니다.

이는 유연한 확장을 가능하게 만들어 주고, 변경이 불필요 하도록 만들어 줍니다.
SOLID 원칙개방-폐쇄 원칙이 지켜진 것입니다.


추가로, Node.js에는 typedi라는 의존성 주입 라이브러리가 있습니다.

간단히 설명하자면 클래스는 의존성을 무한히 가질 수 있습니다. 때문에 새로운 객체를 생성할 때마다 의존성을 주입해 준다면 상당히 번거롭고 비효율적이기 때문에 typedi라는 의존성 주입 도구를 사용하여 구현해, typedi가 제어권을 갖는 주체로 동작하도록 합니다. 이를 제어권의 역전이라고 합니다.

간단히 말해 typedi는 의존성 주입을 자동으로 적용시켜주는 편리한 도구라고 생각하시면 됩니다.

0개의 댓글