본문 바로가기
Thinking/Concept

상태 패턴(State Pattern) 이해하기

by Dev_카페인 2024. 11. 17.
반응형

상태 패턴(State Pattern) 이해하기

상태 패턴객체의 내부 상태에 따라 객체의 행동을 변경할 수 있도록 설계된 행동 디자인 패턴입니다. 이 패턴은 객체의 상태를 별도의 클래스로 캡슐화하여, 상태 전환과 행동 변경 로직을 관리합니다.

상태 패턴은 조건문을 제거하고, 상태에 따른 동작을 상태 객체로 위임함으로써 코드의 복잡성을 줄이고, 유지보수성을 높이는 데 도움을 줍니다.

 

상태 패턴이란?

상태 패턴은 객체의 상태를 별도의 상태 객체로 캡슐화하여, 객체가 상태에 따라 다른 행동을 수행할 수 있도록 설계된 패턴입니다. 객체의 상태가 변경되면 현재 상태를 나타내는 상태 객체가 교체되며, 객체는 상태 객체에 정의된 동작을 수행합니다.

주요 개념은 상태 전환 로직을 객체 내부가 아닌 상태 객체로 분리하여 코드의 유연성과 확장성을 높이는 것입니다.

상태 패턴의 구조

상태 패턴은 다음과 같은 구성 요소로 이루어집니다.

  1. Context (문맥):
    • 상태 객체를 유지하며, 현재 상태에 따라 행동을 위임합니다.
  2. State (상태 인터페이스):
    • 문맥(Context)에 의해 호출될 상태별 행동을 정의합니다.
  3. ConcreteState (구체적인 상태):
    • State 인터페이스를 구현하며, 상태에 따른 행동을 구체적으로 정의합니다.

상태 패턴의 구현 방법

예제 코드: 주문 상태 관리 시스템

온라인 쇼핑몰에서 주문 상태(주문 접수, 배송 중, 배송 완료)를 관리하는 시스템을 상태 패턴으로 구현해보겠습니다.

// State 인터페이스
public interface IOrderState
{
    void ProcessOrder(OrderContext context);
}

// ConcreteState 클래스: 주문 접수 상태
public class OrderReceivedState : IOrderState
{
    public void ProcessOrder(OrderContext context)
    {
        Console.WriteLine("Order received. Preparing for shipment.");
        context.SetState(new ShippingState());
    }
}

// ConcreteState 클래스: 배송 중 상태
public class ShippingState : IOrderState
{
    public void ProcessOrder(OrderContext context)
    {
        Console.WriteLine("Order is being shipped.");
        context.SetState(new DeliveredState());
    }
}

// ConcreteState 클래스: 배송 완료 상태
public class DeliveredState : IOrderState
{
    public void ProcessOrder(OrderContext context)
    {
        Console.WriteLine("Order has been delivered. No further processing required.");
    }
}

// Context 클래스
public class OrderContext
{
    private IOrderState _currentState;

    public OrderContext()
    {
        _currentState = new OrderReceivedState(); // 초기 상태
    }

    public void SetState(IOrderState state)
    {
        _currentState = state;
    }

    public void ProcessOrder()
    {
        _currentState.ProcessOrder(this);
    }
}

// Client 코드
class Program
{
    static void Main()
    {
        OrderContext order = new OrderContext();

        // 주문 상태 처리
        order.ProcessOrder(); // 주문 접수
        order.ProcessOrder(); // 배송 중
        order.ProcessOrder(); // 배송 완료
    }
}

실행 결과

 
Order received. Preparing for shipment.
Order is being shipped.
Order has been delivered. No further processing required.

코드 설명

  1. State:
    • IOrderState 인터페이스는 상태별 행동(ProcessOrder)을 정의합니다.
  2. ConcreteState:
    • OrderReceivedState, ShippingState, DeliveredState 클래스는 각각 주문 접수, 배송 중, 배송 완료 상태에 따른 동작을 구현합니다.
  3. Context:
    • OrderContext 클래스는 현재 상태를 유지하고, 상태 객체에 행동을 위임합니다.
    • 상태가 변경되면 SetState() 메서드를 호출하여 상태 객체를 교체합니다.

 

상태 패턴의 장단점

장점

  1. 조건문 제거:
    • 복잡한 조건문(if-else 또는 switch)을 제거하고, 상태 객체에 행동을 위임하여 코드의 가독성과 유지보수성을 향상시킵니다.
  2. 상태 전환 로직 분리:
    • 상태 전환 로직을 상태 객체로 분리하여, 문맥(Context) 클래스가 상태 전환 로직에 의존하지 않습니다.
  3. 유연성:
    • 새로운 상태를 추가하거나 기존 상태를 수정할 때, 다른 상태나 문맥 클래스에 영향을 주지 않고 확장할 수 있습니다.

단점

  1. 클래스 수 증가:
    • 각 상태를 별도의 클래스나 객체로 구현해야 하므로, 클래스 수가 증가할 수 있습니다.
  2. 상태 전환 복잡성:
    • 상태 전환 로직이 많은 경우, 상태 객체 간의 의존성이 복잡해질 수 있습니다.

 

언제 상태 패턴을 사용해야 할까?

상태 패턴은 다음과 같은 상황에서 유용합니다.

  1. 객체의 동작이 상태에 따라 달라지는 경우:
    • 객체가 여러 상태를 가질 수 있고, 각 상태에서 다른 행동을 수행해야 할 때.
  2. 상태 전환 로직이 자주 변경되거나 확장될 가능성이 있는 경우:
    • 상태 전환 규칙이 자주 변경되거나, 새로운 상태가 추가될 가능성이 높은 경우.
  3. 조건문이 복잡하고 중복이 많은 경우:
    • 상태 전환 로직이 조건문으로 구현되어 복잡한 경우, 상태 패턴으로 단순화할 수 있습니다.

 

상태 패턴과 관련 패턴 비교

상태 패턴은 객체의 상태에 따른 행동 변경과 상태 전환에 초점을 둡니다. 다른 패턴과의 차이를 살펴보겠습니다.

  • 전략 패턴:
    • 알고리즘을 캡슐화하여 동적으로 교체할 수 있도록 하는 패턴입니다. 상태 패턴은 상태 전환 로직을 포함하지만, 전략 패턴은 상태 전환 로직이 없습니다.
  • 옵저버 패턴:
    • 상태 변경을 관찰하는 객체들에게 알림을 보내는 패턴입니다. 상태 패턴은 상태 전환과 동작 변경에 초점이 있습니다.
  • 커맨드 패턴:
    • 요청을 캡슐화하여 나중에 실행하거나 취소할 수 있도록 하는 패턴입니다. 상태 패턴은 객체의 상태와 상태별 행동을 관리합니다.

 

실무에서 상태 패턴 활용하기

상태 패턴은 다음과 같은 실무 상황에서 활용됩니다.

  1. 게임 개발:
    • 캐릭터의 상태(예: 걷기, 점프, 공격)에 따라 행동을 변경하거나 상태 전환을 관리.
  2. 문서 워크플로우 시스템:
    • 문서의 상태(예: 초안, 검토 중, 승인됨)에 따라 다른 작업을 수행.
  3. ATM 시스템:
    • ATM 기기의 상태(예: 카드 삽입 대기, PIN 입력 대기, 거래 중)에 따라 사용자 입력을 처리.
  4. UI 컴포넌트:
    • 버튼, 토글 스위치 등의 상태(예: 활성화, 비활성화, 클릭됨)에 따라 동작 변경.

 

마무리하며

상태 패턴은 객체의 상태와 동작을 분리하여 코드의 가독성과 유지보수성을 높이는 강력한 패턴입니다. 특히, 상태 전환 로직이 복잡하거나 상태에 따라 동작이 달라지는 시스템에서 큰 효과를 발휘합니다.

복잡한 상태 전환 로직이나 상태 기반 행동 변경이 필요한 시스템을 설계할 때, 상태 패턴을 적극적으로 활용해보세요. 이를 통해 코드의 유연성과 확장성을 크게 향상시킬 수 있습니다.

반응형