TypedI
의존성
- 의존성은 구성 요소들이 서로 의존하는 성질입니다.
// 의존성은 구성 요소들이 서로 의존하는 성질입니다.
// Programmer 클래스는 Laptop 클래스에 의존성을 띕니다.
class Laptop {
public turnOn() {}
}
class Macbook extends Laptop {}
class Programmer {
private laptop: Laptop;
constructor() {
this.laptop = new Laptop();
}
public programming() {
this.laptop.turnOn();
}
}
// programmer가 Mabook을 사용한다면 생성자 함수에 Macbook으로 변경해야 하는 이슈가 발생한다.
class Programmer2 {
private laptop: Laptop;
constructor() {
this.laptop = new Macbook();
}
public programming() {
this.laptop.turnOn();
}
}
const programmer: Programmer = new Programmer();
programmer.programming();
- 위 코드에서 Programmer 클래스는 Laptop 클래스에 의존성을 띄게 됩니다.
- 위의 예제에서 Programmer가 평범한 Laptop이 아닌 Macbook을 사용하도록 만들게 되면 2번째와 같은 코드를 수정해야
합니다.
- Laptop 클래스를 상속 받는 Macbook 클래스를 생성하고 Programmer 클래스의 laptop 변수가 Macbook 클래스의
객체를 할당 받도록 수정해주면 됩니다.
- 이럴 경우 Programmer 클래스가 Laptop 클래스에 의존하고 있었기 때문에 Programmer 클래스를 직접 수정해야 하는
번거로움이 생기게 됩니다.
=> 즉 이렇게 의존성은 하나를 변경하면 그것에 의존하는 다른 것들도 모두 변경해야 합니다.
의존성 주입
- 의존성 주입이란 외부에서 의존성을 주입해주느 것을 말합니다.
// 의존성 주입이란 말그대로 외부에서 의존성을 주입해주는 것을 말합니다.
export class Laptop {
public turnOn() {
console.log("programming start");
}
}
export class Macbook extends Laptop {
public turnOn() {
console.log("programming start with Macbook");
}
}
export class Programmer {
private laptop: Laptop;
constructor(laptop: Laptop) {
this.laptop = laptop;
}
public programming() {
this.laptop.turnOn();
}
}
const programmer: Programmer = new Programmer(new Laptop());
const programmer2: Programmer = new Programmer(new Macbook());
// programming start
// programming start with Macbook
- 첫 예제에 의존성 주입을 사용하였습니다. Programmer 클래스가 의존하던 Laptop 클래스의 객체를 외부에서
주입해주고 있습니다.
- Macbook을 사용하는 프로그래머를 만드는 것도 Laptop 클래스의 객체 대신 Macbook 클래스의 객체를 주입해주면
Programmer 클래스를 수정하지 않고도 아주 편리하게 변경사항을 적용할 수 있습니다.
- 이것이 의존성 주입입니다.
의존 관계 역전의 원칙
- 의존 관계 역전의 원칙은 SOLID 원칙 중 하나로, 변화하기 쉬운 것 보단 변화하기 어려운 것에 의존하라는 원칙입니다.
- 예를 들면, 프로그래머들의 구체적으로 어떤 기종을 사용할지는 변화하기 쉬운 것입니다.
하지만 프로그래머들이 노트북만으로 코딩을 한다는 점은 변하기 어렵습니다.
interface Laptop {
turnOn(): void;
}
class Macbook implements Laptop {
public turnOn() {}
}
class Gram implements Laptop {
public turnOn() {}
}
class Programmer {
constructor(private laptop: Laptop) {}
public programming() {
this.laptop.turnOn();
}
}
const programmer1: Programmer = new Programmer(new Macbook());
const programmer2: Programmer = new Programmer(new Gram());
- Macbook 클래스와 Gram 클래스가 Laptop 인터페이스를 구현하고 있습니다.
그리고 Programmer 클래스의 생성자는 Laptop 타입의 인자를 받고 있습니다.
- 따라서 모든 클래스가 Laptop이라는 인터페이스에 의존하게 되고, 이는 일반적인 의존 관계
( 하위 클래스가 상위 클래스에 의존 ) 한다는 것과 다르다는 것을 알 수 있습니다.
- 여기서 Macbook, Gram과 함께 삼성 노트북도 사용하고 싶다면 Laptop 인터페이스를 구현하는 삼성 노트북 클래스를
만들면 됩니다. 삼성 노트북 클래스의 인스턴스를 Programmer에게 주입하더라도 어떤 문제도 발생하지 않습니다.
- 즉 이러한 의존 관계는 유연한 확장을 가능하게 만들고, 변경이 불필요하도록 만듭니다.
이는 SOLID 원칙 중 개방 - 폐쇄 원칙이 지켜진 것입니다.
제어권 역전
- 의존성 주입만 사용하게 되면 우리가 직접 의존성을 관리해야 합니다.
- 하지만 클래스가 가질 수 있는 의존성은 무한합니다. 따라서 새로운 객체를 생성할 때마다 직접 주입해 주는 것은
지루하고 비효율적입니다.
- 그렇기에 TypeI가 존재합니다.!
TypeScript와 typedi로 의존성 주입 이해하기
아름다운 코드를 짜기 위해서 의존성 주입을 알아봅시다.
medium.com