Learn to Code

[디자인패턴] 자바스크립트로 전략 패턴(Strategy Pattern) 구현하기

CEOSEO 2024. 6. 11. 11:21
728x90
반응형

 

1. 전략패턴(Strategy Pattern)이란?

전략 패턴(Strategy Pattern)은 객체의 행위를 바꾸고 싶은 경우 직접 수정하지 않고 전략(알고리즘)을 객체화하여 동적으로 행위를 변경할 수 있게 해주는 디자인 패턴이다. 이 패턴은 여러 알고리즘을 하나의 추상적인 인터페이스로 묶어 알고리즘군을 정의하고, 각 알고리즘을 구체적인 전략 클래스로 캡슐화하여 필요에 따라 서로 교체 가능하게 만든다. 이를 통해 클라이언트는 알고리즘의 내부 구조를 알 필요 없이 유연하게 알고리즘을 변경할 수 있다.

 

 

알고리즘군이란?

- 동일한 기능을 수행하지만 다른 방식으로 구현된 알고리즘들의 모음

 

예)

- "정렬"이라는 동일한 문제를 해결하는 알고리즘 군 안에는 버블정렬, 삽입정렬, 퀵정렬, 병합정렬 등이 있다.

- 이 알고리즘 군에 들어있는 알고리즘들은 모두 "정렬"이라는 동일한 문제를 해결하지만, 각각의 알고리즘은 다른 방식으로 동작한다.

 

 

728x90

 

 

2. 전략 패턴의 주요 장점

1. 유연성 제공:

전략 패턴은 알고리즘을 쉽게 교체할 수 있는 유연성을 제공한다. 예를 들어, 특정 기능을 수행하는 여러 가지 방법이 있을 때, 이 패턴을 사용하면 런타임에 알고리즘을 변경할 수 있다. 이는 다양한 상황에 따라 동적으로 행위를 변경할 수 있게 해준다.

 

2. 코드 재사용성 향상:

알고리즘을 별도의 클래스나 객체로 분리하여 재사용할 수 있게 한다. 여러 클라이언트 객체가 동일한 알고리즘을 공유할 수 있으며, 코드 중복을 줄여준다. 이는 코드의 유지보수를 용이하게 한다.

 

3. 유지보수성 향상:

알고리즘을 각기 다른 클래스에 캡슐화함으로써, 특정 알고리즘의 변경이 다른 코드에 영향을 미치지 않는다. 이는 코드의 수정이 필요한 경우 변경의 범위를 최소화하여 유지보수를 쉽게 한다.

 

4. 확장성 증대:

새로운 알고리즘을 추가할 때 기존 코드를 수정할 필요 없이 새로운 전략 클래스를 추가하면 된다. 이는 시스템의 확장성을 크게 향상시킨다. 새로운 요구사항이 생길 때마다 간단히 새로운 전략을 추가할 수 있다.

 

 

 

3. 전략 패턴의 구조

전략 패턴은 다음과 같은 주요 구성 요소들로 이루어져 있다.

 

1. 컨텍스트(Context):

역할: 클라이언트가 사용할 인터페이스를 제공하며, 알고리즘을 동적으로 변경할 수 있게 해주는 클래스이다. 컨텍스트는 내부적으로 Strategy 객체를 유지하며, 이를 통해 클라이언트가 요청한 작업을 수행한다.

 

 

2. 전략 인터페이스(Strategy Interface):

역할: 알고리즘을 캡슐화하여 여러 알고리즘을 하나의 추상적인 인터페이스로 정의한다. 이를 통해 다양한 알고리즘을 동일한 방식으로 사용할 수 있게 한다.

 

 

3. 구체적인 전략 클래스들(Concrete Strategy Classes):

역할: 전략 인터페이스를 구현하여 실제 알고리즘을 제공하는 클래스들이다. 각 클래스는 특정 알고리즘을 구현하며, 컨텍스트에서 필요에 따라 이 알고리즘을 사용할 수 있다.

 

 

+--------------------+          +--------------------------+
|      Context       |          |      Strategy Interface   |
|--------------------|          |--------------------------|
| - strategy: Strategy |<>--------| + useAlgorithm(): void   |
|--------------------|          +--------------------------+
| + setStrategy(s: Strategy): void |
| + executeStrategy(): void     |
+--------------------+
          |
          | uses
          v
+-------------------------+
|   Concrete Strategy A   |
|-------------------------|
| + useAlgorithm(): void  |
+-------------------------+
          |
          | uses
          v
+-------------------------+
|   Concrete Strategy B   |
|-------------------------|
| + useAlgorithm(): void  |
+-------------------------+
          |
          | uses
          v
+-------------------------+
|   Concrete Strategy C   |
|-------------------------|
| + useAlgorithm(): void  |
+-------------------------+

 

 

 

4. 예시

전략 패턴의 예시를 Player라는 클래스와 4개의 직업 - 전사, 궁수, 마법사, 성직자-, 그리고 각각의 무기 4개 - 검, 활, 지팡이, 메이스 - 로 구현해보자. 이 예시를 위에서 말한 전략 패턴의 주요 구성 요소에 아래와 같이 대입할 수 있다.

 

1. 컨텍스트(Context):

 Player 클래스는 무기 전략을 설정하고, 이를 사용하여 공격하는 역할을 한다. Player 객체는 무기 전략을 변경할 수 있으며, attack 메서드를 호출하면 현재 설정된 전략에 따라 공격 행동을 수행한다.

역할: 클라이언트가 사용할 인터페이스를 제공하며, 무기 사용 전략을 동적으로 변경할 수 있게 해준다.

예시: Player 클래스가 컨텍스트의 역할을 한다.

 

// 플레이어 클래스

class Player {
    constructor(name, strategy) {
        this.name = name;
        this.setStrategy(strategy);
    }

    setStrategy(strategy) {
        if (!(strategy instanceof WeaponStrategy)) {
            throw new Error("전략은 WeaponStrategy의 인스턴스여야 합니다.");
        }
        this.strategy = strategy;
    }

    attack() {
        console.log(`${this.name}이(가) ${this.strategy.useWeapon()}`);
    }
}

 

 

2. 전략 인터페이스(Strategy Interface):

WeaponStrategy 클래스는 무기 사용 방법을 정의하는 추상 클래스이다. useWeapon 메서드는 각 무기 전략 클래스가 구현해야 하는 메서드이다. 이 인터페이스를 통해 Player 클래스는 구체적인 무기 사용 방법을 알 필요 없이, 무기를 사용할 수 있다.

역할: 무기 사용 방법을 캡슐화하여 여러 무기 사용 전략을 하나의 추상적인 인터페이스로 정의한다.

예시: WeaponStrategy 클래스가 전략 인터페이스의 역할을 한다.

 

// WeaponStrategy 인터페이스

class WeaponStrategy {
    useWeapon() {
        throw new Error("useWeapon 메서드를 구현해야 합니다.");
    }
}

 

 

3. 구체적인 전략 클래스들(Concrete Strategy Classes):

역할: 전략 인터페이스를 구현하여 실제 무기 사용 방법을 제공하는 클래스들이다. 각 클래스는 특정 무기 사용 방법을 구현한다.

예시: SwordStrategy, BowStrategy, StaffStrategy, MaceStrategy 클래스들이 구체적인 전략 클래스들이다.

 

// 구체적인 전략 클래스

class SwordStrategy extends WeaponStrategy {
    useWeapon() {
        return "검으로 공격합니다!";
    }
}

class BowStrategy extends WeaponStrategy {
    useWeapon() {
        return "활로 공격합니다!";
    }
}

class StaffStrategy extends WeaponStrategy {
    useWeapon() {
        return "지팡이로 공격합니다!";
    }
}

class MaceStrategy extends WeaponStrategy {
    useWeapon() {
        return "메이스로 공격합니다!";
    }
}

 

 

사용예시)

const warrior = new Player("전사", new SwordStrategy());
warrior.attack();  // 전사가 검으로 공격합니다!

const archer = new Player("궁수", new BowStrategy());
archer.attack();  // 궁수가 활로 공격합니다!

const mage = new Player("마법사", new StaffStrategy());
mage.attack();  // 마법사가 지팡이로 공격합니다!

const cleric = new Player("성직자", new MaceStrategy());
cleric.attack();  // 성직자가 메이스로 공격합니다!

 

 

 

 

728x90
반응형