Strategy Pattern :: iopeni - Think of C#


Head First - Design Pattern 에 정의 하길....

Strategy Pattern에서는 알고리즘군을 정의하고 각각을 캡슐화하여 교환해서 사용할 수 있도록 만든다. 스트레티지를 활용하면 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경 할 수 있다.


위 정의만을 놓고 보자면 도대체 이게 무슨 소리 인지 이해하기가 쉽지 않네요.


일단 스트레티지 패턴을 이해 하기 위하여, 몇 가지 사전 지식이 필요합니다.


1. 추상클래스

2. 인터페이스

3. 상속

4. 업.다운캐스팅


수 많은 프로그래밍 구루들이 이야기 하길 사실 프로그래밍을 하기 위하여 꼭 알아야 하는 것으로 상속과 추상클래스, 인터페이스 보다 중요한 것은 없다고 이야기들을 합니다.


스트래티지 패턴은 위에서 언급한 4가지 개념으로 만들어 집니다. 만일 위 4가지 개념중 한가지라도 좀 미흡하다 싶은 분께서는 먼저 저 4가지 개념 부터 다시 학습 하신다음에 스트레티지 패턴을 보시면 이해 하기가 훨씬 용이할 겁니다.


이제 스트레티지 패턴을 풀어 보도록 하죠


한국 사람이라면 누구나 수저를 이용하여 밥을 먹을 껍니다. 그런데 사실 우리 와이프는 저보다 젓가락질을 잘 못합니다.


이게 바로 스트레티지 패턴의 전형적인 예 입니다.


어떤 사람은 밥을 먹을때 포크와 숟가락 으로만 먹을 것이며, 어떤 사람은 숟가락으로만 ... 어떤 사람은 젓가락으로만... 뭐 이렇게  밥을 먹을때도 각각의 사람들은 각각의 자기만의 밥 먹는 방법이 있을 겁니다. 그냥 이렇게만 한정 지어 버린다면 이 문제를 상속과 추상클래스 만으로 풀어 내려고 해도 됩니다. 아주 훌륭한 방법이 되겠죠.


그런데 어느날 갑자기 우리 와이프가 젓가락질을 겁내 열심히 연습해서 저보다 젓가락질을 잘 하게 될 수도 있을 겁니다. 그럼 행동 패턴이 바뀌게 됩니다. 지금은 젓가락질을 잘 못하기 때문에 숟가락으로만 밥을 먹다가... 어느날 갑자기 수저로 밥을 먹게 되어 버린거죠. 행위의 속성이 한가지 추가 되어 버린겁니다. 


이렇게 되어 버리면 상속이나 추상으로만 놓고 보면 추 후 유지보수측면에서만 바라 보더라도 좀 곤란한 상황이 발생 하게 될 수도 있습니다. 


좀 더 확장해서 생각해 보면 상속이나 추상으로만 해결 하였을 경우 우리 와이프가 젓가락질을 잘 못한다고 우리 와이프의 뱃속에서 태어나 자란 아이가 젓가락질을 잘 못할 수도 있겠지만... 저를 닮아서 잘 할 수도 있다는 점이죠... 


결국 행위에 대한 정의는 쉽게 변경 될 수 있으나 상속을 통해서 행위에 대한 정의를 변형 하려고 하면 부모로 부터 상속 받은 문제등으로 인하여 곤란한 상황이 될 수 있을 거라는 뜻 입니다. 


이런 문제를 해결 하기 위한 것이 인터페이스이며, 이 인터페이스를 활용하여 우리의 프로그래밍 구루 몇분께서 스트레티지 패턴을 만들어 놓으셨습니다.


스트레티지 패턴을 구현하기에 앞서 우리가 먼저 외워야 할 것들이 있습니다.


1. Application에서 달라지는 부분(행위)과 달라지지 않는 부분(몸체)을 구분하여 분리 하여야 한다.

2. 상위 형식에 맞추어 프로그래밍 하라.(업캐스팅) - A=B 이다가 아니라. A에는 B가 있다는 것이 훨씬 좋을 수 있으므로 인터페이스를 선언하고 상위 형식으로 인터페이스를 이용하는 방법 이 좋을 수 있다는 뜻 입니다.



using System;

namespace Strategy
{
    public class MiniDuckSimulator
    {
        static void Main(string[] args)
        {
            Duck mallard = new MallardDuck();
            mallard.Display();
            mallard.PerformQuack();
            mallard.PerformFly();

            Console.WriteLine("");

            Duck model = new ModelDuck();
            model.Display();
            model.PerformFly();

            //런타임에 날 수 없는 장난감 오리를 겁내 빨리 날도록 바꿨어요.
            model.FlyBehavior = new FlyRocketPowered();
            model.PerformFly();

            Console.ReadKey();
        }
    }

    #region Duck

    public abstract class Duck
    {
        public IFlyBehavior FlyBehavior { get; set; }
        public IQuackBehavior QuackBehavior { get; set; }

        public abstract void Display();

        public void PerformFly()
        {
            // A에는 B가 있다.
            FlyBehavior.Fly();
        }

        public void PerformQuack()
        {
            QuackBehavior.Quack();
        }

        public void Swim()
        {
            Console.WriteLine("모든 오리는 물위에 뜰 수 있어요.");
        }

    }

    public class MallardDuck : Duck
    {
        public MallardDuck()
        {
            //인터페이스 업캐스팅
            QuackBehavior = new LoudQuack();
            FlyBehavior = new FlyWithWings();
        }

        override public void Display()
        {
            Console.WriteLine("나는 청둥오리예요");
        }
    }

    public class ModelDuck : Duck
    {
        public ModelDuck()
        {
            // 인터페이스 업캐스팅
            QuackBehavior = new LoudQuack();
            FlyBehavior = new FlyNoWay();
        }

        override public void Display()
        {
            Console.WriteLine("나는 실제 오리가 아니라 장난감 오리예요.");
        }
    }

    #endregion

    #region FlyBehavior

    public interface IFlyBehavior
    {
        void Fly();
    }

    public class FlyWithWings : IFlyBehavior
    {
        public void Fly()
        {
            Console.WriteLine("나는 날아 다녀요.");
        }
    }
    public class FlyNoWay : IFlyBehavior
    {
        public void Fly()
        {
            Console.WriteLine("나는 날지 못해요!");
        }
    }
    public class FlyRocketPowered : IFlyBehavior
    {
        public void Fly()
        {
            Console.WriteLine("나는 겁내 빨리 날아다녀요!");
        }
    }
    #endregion

    #region QuackBehavior

    public interface IQuackBehavior
    {
        void Quack();
    }

    public class LoudQuack : IQuackBehavior
    {
        public void Quack()
        {
            Console.WriteLine("크게 소리내요");
        }
    }

    public class MuteQuack : IQuackBehavior
    {
        public void Quack()
        {
            Console.WriteLine("나는 조용한 오리라구요.");
        }
    }

    public class Squeak : IQuackBehavior
    {
        public void Quack()
        {
            Console.WriteLine("작게 소리내요.");
        }
    }
    #endregion
}



Posted by 프로그래머란 카페인을 코드로 변환하는 기계다
,