22. 상태 패턴(State Pattern) 구현

22.4 구현

상태 패턴에 대한 예제 프로그램을 구현하는 순서는 Iris와 Shutter, State 군, Camera와 데모 코드 순으로 하겠습니다.

22.4.1 Iris와 Shutter

Iris와 Shutter는 단순히 조리개의 F값과 셔터 스피드를 조절하는 역할만 수행합니다. 특별히 상태 패턴과 관련이 있는 형식은 아닙니다.

▶ Iris.cs 

namespace State
{
    class Iris
    { 
        int focal_length = 2;
        public int Up()
        {
            if(focal_length<10)
            {
                focal_length++;		
            }
            return focal_length;
        }
        public int Down()
        {
            if(focal_length>2)
            {
                focal_length--;
            }
            return focal_length;
        }
    }
}

▶ Shutter.cs 

namespace State
{
    class Shutter
    {
        int speed =0;
        public int Up()
        {
            speed++;		
            return speed;
        }
        public int Down()
        {
            if(speed>0)
            {
                speed--;
            }
            return speed;
        }	
    }
}

22.4.2 State 군

IState 인터페이스에서는 값을 올리거나 내리는 행위에 대한 약속만 하면 됩니다. 대신 OnState와 OffState에서는 약속된 구체적 행위를 정의를 해야 할 것입니다. OnState에서는 Shutter 개체를 이용하여 셔터 스피드를 조절해야 할 것이며 OffState에서는 Iris 개체를 이용하여 조리개의 F값을 조절합니다.

▶ IState.cs 

namespace State
{
    interface IState
    {
        void Up();
        void Down();
    }
}

▶ OnState.cs 

using System;
namespace State
{
    class OnState:IState
    {
        Shutter shutter;
        public OnState(Shutter shutter)
        {
            this.shutter = shutter;
        }
        public void Up()
        {
            Console.WriteLine("셔터 스피드 올라감. 현재 스피드:{0}",shutter.Up());
        }
        public void Down()
        {
            Console.WriteLine("셔터 스피드 내려감. 현재 스피드:{0}",shutter.Down());
        }
    }
}

▶ OffState.cs 

using System;
namespace State
{
    class OffState:IState
    {
        Iris iris;
        public OffState(Iris iris)
        {
            this.iris = iris;
        }
        public void Up()
        {
            Console.WriteLine("F 값 증가되었음. 현재 F값:{0}", iris.Up());
        }
        public void Down()
        {
            Console.WriteLine("F 값 감소되었음. 현재 F값:{0}", iris.Down());
        }       
    }
}

22.4.3 Camera와 데모 코드

Camera에서는 정보 버튼을 눌러지는 상태를 변경하는 메서드를 제공할 것입니다. 그리고, 다이얼을 통해 값을 높이거나 내릴 수 있는 메서드를 제공할 것입니다. 내부에서는 정보 버튼의 눌러진 상태가 바뀌면 이에 대한 정보를 유지하고 있게 하여 다이얼을 통해 값을 높이거나 내리는 메서드에서는 상태 개체를 이용합니다.

상태 패턴을 사용하지 않았다면 값을 올리거나 내리는 메서드에서 자신의 상태에 따라 셔터를 사용하거나 조리개를 사용하는 것을 직접 구현하였을 것입니다. 만약, 카메라의 상태가 좀 더 다양하고 각 상태에 따라 하는 구체적 행위가 다르다면 카메라 클래스는 거대해질 것입니다. 경우에 따라 구체적 행위에 사용하는 기술이 다를 경우에 카메라를 정의하는 개발자는 업무가 과해질 수 있습니다. 이와 같은 경우에 상태 패턴을 사용하면 상태가 추가되거나 감소되더라도 유연하게 대처할 수 있고 효과적으로 작업 분배를 할 수 있겠죠.

▶ Camera.cs 

namespace State
{
    class Camera
    {
        Shutter shutter = new Shutter();
        Iris iris = new Iris();
        IState[] states = new IState[2];
        int statenum=0;
        public Camera()
        {
            states[0] = new OffState(iris);
            states[1] = new OnState(shutter);
        }
        public void ToggleInfoButton()
        {
            statenum = (statenum+1)%2;
        }
        public void DialUp()
        {
            states[statenum].Up();     
        }
        public void DialDown()
        {
            states[statenum].Down();
        }
    }
}

 데모 코드에서는 카메라의 정보 버튼을 누르지 않은 상태에서 다이얼을 통해 값을 올리거나 내려보고 정보 버튼을 누른 상태에서 다시 해당 작업을 수행하게 합시다.

▶ Program.cs  

namespace State
{
    class Program
    {
        static void Main(string[] args)
        {
            Camera camera = new Camera();
            camera.DialUp();
            camera.DialDown();
            camera.ToggleInfoButton();
            camera.DialUp();
            camera.DialDown();
        }
    }
}

▶ Program.cs  

F 값 증가되었음. 현재 F값:3
F 값 감소되었음. 현재 F값:2
셔터 스피드 올라감. 현재 스피드:1
셔터 스피드 내려감. 현재 스피드:0