Dependency Inversion Principle is specific form of Loosly Coupling software modules
일반적으로 상위 모듈은 하위모듈에 의존적인데 이러한 의존관계를 뒤집는 것이다. 의존관계를 뒤집으면 아래와 같은 장점이 있다.
1. 코드가 유연해진다 : 하위모듈을 변경하여도 상위모듈을 수정할 필요가 없다.
2. 재사용성 : 공통인터페이스나 추상화로 모듈의 결합도를 낮추고 코드중복을 줄인다.
3. 테스트 용이성 : 의존성을 줄여서 테스트하기 편리하다.
4. 유지보수성 : 모듈간의 의존성이 줄어들어 코드를 변경할때 생기는 부작용이 감소한다.
상위모듈 -> 하위모듈 의 의존관계를
상위모듈(하위모듈의 컬렉션을 속성으로 가짐) -> (하위모듈의)추상계층 <- 하위모듈(컬렉션의 원소, )로 변경하는것
기업이 김코딩이라는
노드 개발자의 인스턴스에 의존하는게 아니라노드 개발자에 의존해야된다. 그러면 김코딩이 퇴사한다고 해도 다른 노드 개발자설냥이가 들어오면 변경없이 개발팀이 잘 돌아가게 됨.
// bad example 💩
class Pikachu {
speak() {
console.log('pika');
}
}
class Evee {
speak() {
console.log('eveeeeee');
}
}
class Ggobugi {
speak() {
console.log('bugibugi');
}
}
// Gym 라는 하이레벨 모듈이 포켓몬인 로우레벨 모듈들을 가지고 있다.
// 만약 포켓몬을 더 많이 Gym에 넣으려면 매번 Gym클래스를 직접 수정해야해서 불편하다.
class Gym {
constructor(
public pikachoo: Pikachu,
public evee: Evee,
public ggobugi: Ggobugi
) {
this.pikachoo = new Pikachu();
this.evee = new Evee();
this.ggobugi = new Ggobugi();
}
}
// 따라서 추상클래스 계층 또는 인터페이스를 Gym과 구체적인 포켓몬 사이에 삽입한다.
// DI_Gym은 구체적인 포켓몬에 의존적이지 않고 Abstract Layer인 Pokemon에 의존적이다.
// 따라서 파이리나 잠만보같인 새로운 포켓몬을 추가하더라도 DI_Gym 클래스는 변경할 필요가 없다.
// 확장에는 열러있고 변경에는 닫혀있는 형태의 DI_Gym이 완성되었다.
// Good example ⭐
class Pokemon {
speak(): void {
return;
}
}
class DI_Gym {
constructor(public monsters: Pokemon[] = []) {}
addMonster(monster: Pokemon) {
this.monsters.push(monster);
}
speakAll() {
this.monsters.forEach((elem) => elem.speak());
}
}
class Pikachu extends Pokemon {
speak() {
console.log('pika')
}
}
const di_gym = new DI_Gym()
di_gym.addMonster(new Pikcahu())
di_gym.speakAll();
// 또가스 클래스를 추가하여도 di_gym의 코드는 변경할 필요가 없다!!
class ddogas extends Pokemon {
speak() {
console.log('ddoga-ddoga')
}
}
di_gym.addMonster(new ddogas())
di_gym.speakAll()