10장 : 상태 패턴
스테이트 패턴
스테이트 패턴을 이용하면 객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다.
언제 사용 ?
현재 상태에 따라 다르게 행동하는 객체가 있을 때, 상태들의 수가 많을 때, 상태별 코드가 자주 변경될 때
크랠스 필드들의 현재 값들에 따라 클래스가 행동하는 방식을 변경하는 거대한 조건문들로 오염된 클래스가 있을 때
유사한 상태들에 중북 코드와 조건문 기반 상태가 많을 때
구현 방법
1️⃣ 어떤 클래스가 콘텍스트로 작동할지 결정한다.
이는 상태에 의존하는 코드가 이미 있는 기존 클래스일 수 있고, 상태별 코드가 여러 클래스에 분산된 경우 새로운 클래스일 수도 있습니다.
2️⃣ 상태 인터페이스를 선언한다.
3️⃣ 모든 실제 상태에 대해 상태 인터페이스에서 파생된 클래스들을 만든다.
4️⃣ 콘텍스트 클래스에서 상태 인터페이스 유형의 참조 필드와 필드의 값을 오버라이드할 수 있는 public setter를 추가한다.
5️⃣ 빈 상태 조건문들을 상태 객체에 해당하는 메서드들에 대한 호출들로 바꿔준다.
6️⃣ 콘텍스트의 상태를 전환하려면 상태 클래스 중 하나의 인스턴스를 만든 후 콘텍스트에 전달한다.
장단점
장점
단일 책임 원칙
특정 상태들과 관련된 코드를 별도의 클래스들로 구성
개방/폐쇄 원칙
기존 상태 클래스들 또는 콘텍스트를 변경하지 않고 새로운 상태들을 도입 가능
거대한 상태 머신 조건문들을 제거하여 콘텍스트의 코드 단순화 가능
단점
상태 머신에 몇 가지 상태만 있거나 머신이 거의 변경되지 않을 때 상태 패턴을 적용하는 것은 과도할 수 있습니다.
스테이터 패턴 vs 스트래티지 패턴
스테이트 패턴을 사용할 때는 상태 객체에 일련의 행동이 캡슐화된다. 상황에 따라 Context 객체에서 여러 상태 객체 중 한 객체에게 모든 행동을 맡기게 된다. 그 객체의 내부 상태에 따라 현재 상태를 나타내는 객체가 바뀌게 되고, 그 결과로 컨텍스트 객체의 행동도 자연스럽게 바뀌게 된다. 클라이언트는 상태 객체에 대해서 거의 아무것도 몰라도 된다.
하지만 스트래티지 패턴을 사용할 때는 일반적으로 클라이언트에서 컨텍스트 객체한테 어떤 전햑 객체를 사용할지를 지정해 준다. 스트래티지 패턴은 주로 실행시에 전략 객체를 변경할 수 있는 유연성을 제공하기 위한 용도롤 쓰인다.
일반적으로 스트래티지 패턴은 서브클래스를 만드는 방법을 대신하여 유연성을 극대화하기 위한 용도로 쓰인다. 상속을 이용해서 클래스의 행동을 정의하다 보면 행동을 변경해야 할 때 마음대로 변경하기 힘들다. 하지만 스트래티지 패턴을 사용하면 구성을 통해 행동을 정의하는 객체를 유연하게 바꿀 수 있다.
스테이트 패턴은 컨텍스트 객체에 수많은 조건문을 집어넣는 대신에 사용할 수 있는 패턴이다. 행동을 상태 객체 내에 캡슐화시키면 컨텍스트 내의 상태 객체를 바꾸는 것만으로도 컨텍스트 객체의 행동을 바꿀 수 있다.
복습
스테이트 패턴 : 상태를 기반으로 하는 행동을 캡슐화하고 행동을 현재 상태한테 위임한다.
스트래티지 패턴 : 알고리즘의 각 단계를 구현하는 방법을 서브클래스에서 구현한다.
템플릿 메소드 패턴 : 바꿔 쓸 수 있는 행동을 캡슐화한 다음, 실제 행동은 다른 객체에 위임한다.
핵심 정리
스테이트 패턴을 이용하면 내부 상태를 바탕으로 여러 가지 서로 다른 행동을 사용할 수 있다.
스테이트 패턴을 사용하면 프로시저형 상태 기계를 쓸 때와는 달리 각 상태를 클래스를 이용하여 표현하게 된다.
Context 객체에서는 현재 상태에게 행동을 위임한다.
각 상태를 클래스로 캡슐화함으로써 나중에 변경시켜야 하는 내용을 국지화시킬 수 있다.
스테이트 패턴과 스트래티지 패턴의 클래스 다이어그램은 똑같지만 그 용도는 서로 다릅니다.
스트래티지 패턴에서는 일반적으로 행동 또는 알고리즘을 Context 클래스를 만들 때 설정한다.
스테이트 패턴을 이용하면 Context의 내부 상태가 바뀜에 따라 알아서 행동을 바꿀 수 있도록 할 수 있다.
상태 전환은 State 클래스에 의해서 제어할 수도 있고, Context 클래스에 의해서 제어할 수도 있다.
스테이트 패턴을 이용하면 보통 디자인에 필요한 클래스의 개수가 늘어난다.
State 클래스를 여러 Context 객체의 인스턴스에서 공유하도록 디자인할 수도 있다.
Refactoring Guru Code
Last updated