728x90

Inhertiance(상속)의 문제를 해결하기위해 Composition(구성)을 사용한다.

상속은 다음과 같은 문제점이 있다.

  1. 상속의 깊이가 깊어어질수록 관계가 복잡해진다.
  2. 상속은 두 부모로부터 받을 수 없다.

Favor Composition Over Inheritance

상속이 나쁜것은 아니지만 확장이 가능하고 더 유연한 Composition을 적극적으로 사용해보도록 하자.

 


 

의존성(Dependency Injection) 주입

Composition에 대해 알아보기 이전에 옳은 Composition을 구현하기 위해 의존성의 문제에 대해서도 알아보자

의존성이란 어느 한 클래스가 다른 클래스를 참조하면서 생기는 두 클래스간의 연결이다.

의존성이 생긴 Class의 예시는 다음과 같다.

class PokemonMaster {
    private MonsterBall monsterBall; // MonsterBall 클래스에 의존성이 생긴다.

    public PokemonMaster() {
        this.monsterBall = new MonsterBall(); 
    }

    public throwMonsterBall() {
        this.monsterBall.gotcha(); //잡았다
        ...
    }
}

위의 코드는 PokemonMaster 클래스가 MonsterBall 클래스의 의존하고 있다.

만약 MonsterBall이 아닌 SuperBall이나 HyperBall을 던지고 싶다면 어떻게 해야할까?

PokemonMaster 클래스를 여러개 받거나 constructor 내부에서 몬스터볼의 instance를 종류대로 생성해야할까?

또한 MonsterBall 클래스의 함수가 변경되면 매번 PokemonMaster 클래스도 수정해 줘야하는걸까?

결합도가 너무 높아 이만저만 문제가 아니다

 

이 의존성 문제를 해결하기위해 Composition을 이용한 의존성 주입의 개념을 가져온다.

  • Unit Test가 용이해진다.
  • 코드의 재활용성을 높여준다.
  • 객체 간의 의존성(종속성)을 줄이거나 없엘 수 있다.
  • 객체 간의 결합도이 낮추면서 유연한 코드를 작성할 수 있다.

의존성 주입의 기본 개념은

constructor의 매개변수의 타입을 interface또는 최상단 class로 하여

instance 생성할때 다른 클래스와 결합이 이뤄지도록 한다는 것이다.

 

위의 예시를 의존성 주입으로 해결해보면 다음과 같다.

interface PokemonBall{
  gotcha():void;
}

class MonsterBall implements PokemonBall{
  gotcha(){
    console.log("monsterBall");
  }
};
class SuperBall implements PokemonBall {
  gotcha(){
    console.log("superBall");
  }
};

class PokemonMaster {
    private pokemonBall: PokemonBall; // MonsterBall 클래스에 의존성이 생긴다.

    constructor(pokemonBall:PokemonBall) {
        this.pokemonBall = pokemonBall; 
    }

    public throwMonsterBall() {
        this.pokemonBall.gotcha(); //잡았다
    }
}

const Red = new PokemonMaster(new MonsterBall());
const Blue = new PokemonMaster(new SuperBall());

Red.throwMonsterBall();
Blue.throwMonsterBall();

이제는 MonsterBall, SuperBall뿐만 아니라 MasterBall이 추가되어도 PokemonMaster가 사용할 수 있게 될 것이다.

+ Recent posts