본문 바로가기
컴퓨터 과학/디자인패턴

[디자인패턴] 행위 패턴(10) : 전략(Strategy)

by webcodur 2024. 3. 25.
728x90
반응형

목차

     

    전략(Strategy)

    전략(Strategy) 디자인 패턴은 행동 디자인 패턴의 하나로, 실행 중에 알고리즘을 선택할 수 있게 해주는 패턴이다. 클라이언트가 직접 알고리즘을 선택할 수 있도록 하거나 알고리즘을 자동으로 선택하게 할 수 있다. 이 패턴의 핵심은 알고리즘의 사용과 알고리즘의 구현을 분리하는 것이다. 이로 인해 동일한 문제를 해결하는 다양한 방법들을 쉽게 교체할 수 있게 해준다. 예를 들어, 정렬이나 필터링과 같은 작업을 다양한 방식으로 구현할 수 있으며, 상황에 따라 가장 적합한 방법을 선택할 수 있다.

    전략 패턴의 어원은 군사학에서 유래했다고 볼 수 있다. '전략'이라는 단어는 군대의 운용, 즉 큰 그림을 계획하는 방법을 의미한다. 소프트웨어 설계에서 이 용어는 비즈니스 로직이나 알고리즘의 계획을 가리키는데 사용된다.

    전략 패턴의 기본 구성요소는 다음과 같다:

    • Strategy: 여러 알고리즘 중 하나의 일반적인 인터페이스를 정의한다.
    • ConcreteStrategy: Strategy 인터페이스를 구현하는, 실제 알고리즘의 클래스들이다.
    • Context: Strategy 객체를 사용하는 역할을 한다. 필요에 따라 적절한 ConcreteStrategy 객체로 대체할 수 있다.

     

    패턴 미적용 예시

    게임 개발 시나리오에서 다양한 캐릭터가 존재하고, 각 캐릭터가 공격하는 방식이 다를 경우를 생각해보자. 패턴을 적용하지 않았을 때의 문제는, 공격 방식의 변화나 새로운 공격 방식의 추가가 어렵다는 것이다. 모든 캐릭터에 대한 공격 메서드를 개별적으로 구현해야 하며, 공격 방식을 변경하려면 해당 캐릭터의 코드를 수정해야 한다.

    public class Knight
    {
        public void Attack()
        {
            Console.WriteLine("검으로 공격한다.");
        }
    }
    
    public class Archer
    {
        public void Attack()
        {
            Console.WriteLine("활로 공격한다.");
        }
    }
    
    public class Wizard
    {
        public void Attack()
        {
            Console.WriteLine("마법으로 공격한다.");
        }
    }
    

     

    패턴 적용 예시

    전략 패턴을 적용하여 게임 캐릭터의 공격 방식을 다루는 예시를 구성하면 다음과 같다. 이 접근 방식을 통해 공격 방식을 캐릭터로부터 분리함으로써, 새로운 공격 방식을 쉽게 추가하거나 기존 공격 방식을 변경할 수 있게 된다.

    // Strategy 인터페이스 정의
    public interface IAttackStrategy
    {
        void Attack(); // 공격을 정의하는 메서드
    }
    
    // ConcreteStrategy 클래스들 정의
    public class SwordAttack : IAttackStrategy
    {
        public void Attack()
        {
            Console.WriteLine("검으로 공격한다."); // 검 공격 구현
        }
    }
    
    public class BowAttack : IAttackStrategy
    {
        public void Attack()
        {
            Console.WriteLine("활로 공격한다."); // 활 공격 구현
        }
    }
    
    public class MagicAttack : IAttackStrategy
    {
        public void Attack()
        {
            Console.WriteLine("마법으로 공격한다."); // 마법 공격 구현
        }
    }
    
    // Context 클래스
    public class Character
    {
        private IAttackStrategy attackStrategy; // 현재 공격 전략
    
        public Character(IAttackStrategy attackStrategy)
        {
            this.attackStrategy = attackStrategy; // 초기 공격 전략 설정
        }
    
        public void SetAttackStrategy(IAttackStrategy strategy)
        {
            this.attackStrategy = strategy; // 공격 전략 변경
        }
    
        public void Attack()
        {
            attackStrategy.Attack(); // 설정된 공격 전략으로 공격
        }
    }
    
    // Program 클래스
    class Program
    {
        static void Main(string[] args)
        {
            // 캐릭터 생성 및 공격 전략 설정
            Character knight = new Character(new SwordAttack());
            knight.Attack(); // "검으로 공격한다." 출력
    
            // 공격 전략 변경
            knight.SetAttackStrategy(new MagicAttack());
            knight.Attack(); // "마법으로 공격한다." 출력
    
            // 다른 캐릭터 생성 및 공격
            Character archer = new Character(new BowAttack());
            archer.Attack(); // "활로 공격한다." 출력
        }
    }
    
    

     

    이 예시에서 Character 클래스는 Context 에 해당하며, IAttackStrategy 인터페이스와 이를 구현하는 SwordAttack, BowAttack, MagicAttack 클래스는 각각 Strategy ConcreteStrategy에 해당한다.

     

    Character 클래스는 공격 방식을 쉽게 변경할 수 있도록 SetAttackStrategy 메서드를 통해 언제든지 다른 IAttackStrategy를 받아들일 수 있다.

     

    이를 통해 공격 방식이라는 알고리즘의 변화에 유연하게 대응할 수 있으며, 새로운 공격 방식이 추가되더라도 Character 클래스를 변경하지 않고도 쉽게 확장할 수 있다는 장점이 있다.

     

    반응형