Skip to content

Commit 7a15c35

Browse files
committed
add: 24/03/18 State Pattern
1 parent b3aaea1 commit 7a15c35

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
## State Pattern
2+
3+
> 객체 내부의 상태를 객체로 만들어라.
4+
5+
### 상태 패턴이란?
6+
7+
상태 패턴은 객체가 자신의 내부 상태에 따라 스스로 행동을 변경할 수 있게 허가하는 패턴. **상태에 따라 달라지는 공통적인 행동들을 인터페이스나 추상 클래스로 추상화**하고, **각 상태의 행동들을 구체화한 상태 클래스들을 생성**해둔 후, **Context 객체가 본인이 가진 상태 클래스를 서로 다른 상태 클래스로 변경하면서 상태의 변화를 묘사**함. 이 일련의 과정은 객체가 행동을 변경할 때, 클래스 자체를 변경한 것처럼 보일 수 있음.
8+
9+
> Context(Context) 객체는 **상태를 가지는 객체**로 보통, 사용자가 실제로 다루는 객체를 의미함.
10+
11+
### 상태 패턴의 등장 배경
12+
13+
상태 패턴은 **유한 상태 기계**(Finite State Machine)과 밀접한 관계가 있음. 핵심 개념은 **모든 주어진 순간에 프로그램이 가질 수 있는 상태의 수는 유한하다**는 것. 모든 프로그램은 상태에 따라 서로 다른 행동을 하며, 프로그램은 현재 상태에 따라 특정 상태로 전환되거나 전환되지 않을 수도 있음. 이러한 전환 규칙들을 **전이**(Transition)라고 함. 상태와 마찬가지로 전이 역시 유한함. 이러한 개념을 객체에 적용한 예로, TCP 통신 기능을 제공하는 `TCPConnection` 객체를 들 수 있음.
14+
15+
**`TCPConnection` 객체가 가지는 상태들**
16+
17+
1. 연결 성공(Established)
18+
2. 대기(Listening)
19+
3. 연결 종료(Closed)
20+
21+
`TCPConnection` 객체는 위와 같이 3개의 **유한한** 상태를 가지고 있으며, 각 상태 간의 전환 역시 **유한함**. 또한, 각 상태에 따라 행동이 달라져야 한다는 것도 알 수 있음. 예를 들어, "연결 성공" 상태일 때와 "연결 종료" 상태일 때의 데이터 전송 요청은 전혀 다른 처리 결과를 반환함. 당연한 얘기지만 연결 성공 상태에서는 데이터 전송 요청도 성공하겠지만 연결이 되어 있지 않은 연결 종료 상태에서는 데이터 전송 요청은 실패해야함.
22+
23+
이렇게 상태에 따라 객체의 행동이 실행 시간 중에 변경되어야 할 경우 조건 분기(`if`문)를 활용하는 것도 방법이 될 수 있음. 그러나 상태가 다양해지면 그만큼 조건 분기가 매우 많아질 것이고(상태에 따른 서로 다른 행동들을 모두 작성해줘야 함!), 객체의 상태를 표현하기 위해 추가적인 열거형을 정의한다거나 같은 조건 분기라도 상태에 맞춰 중복해서 작성해줘야(만약 조건 분기나 행동이 달라지면 수정해야하는 코드도 많아진다.) 하는 등, 불필요한 작업을 해야함.
24+
25+
이때, **객체의 각 상태를 별도의 객체로 정의**하면 다른 객체들과 상관 없이 해당 **객체의 상태를 다양화**하고 단순히 가지고 있던 **상태 객체를 변경하는 것만으로도 객체가 서로 다른 행동을 할 수 있도록 만들 수 있음**. 이것이 상태 패턴의 등장 이유임.
26+
27+
### 상태 패턴의 구조
28+
29+
![statepattern](https://github.com/hangillee/TIL/assets/14046092/d9ec67d8-1812-4382-ba52-a6f733fe7dd6)
30+
31+
상태 패턴은 위와 같은 구조를 가지고 있고, 구성 요소는 다음과 같음.
32+
33+
- **컨텍스트**(Context): 사용자가 실제로 다루는 객체. 상태에 따라 서로 다른 행동을 하게 되는 주체.
34+
- **상태**(State): Context의 각 상태를 추상화한 객체. 각 상태별로 필요한 행동을 캡슐화함.
35+
- **구체적 상태**(State의 서브클래스들): 각 서브클래스는 상태에 따라 처리되어야 할 서로 다른 행동을 구현함.
36+
37+
### 상태 패턴의 동작 방식
38+
39+
- 사용자로부터 요청을 받으면 Context 클래스는 요청을 현재 구체적 상태(서브클래스)로 전달함.
40+
- Context 클래스는 실제 연산을 처리할 상태 객체에 자기 자신을 매개변수로 전달함. 이렇게하면 상태가 Context의 정보에 접근할 수 있음.
41+
- 처음 상태와 연결될 때를 제외하곤, Context 클래스의 상태를 사용자가 직접 변경할 필요 없이 요청만 보내면 Context 클래스가 알아서 전이함.
42+
- Context 클래스, 혹은 구체적 상태들이 자신의 다음 상태가 무엇이고 어떻게 전이할지 결정할 수 있음. 즉, 한 상태에서 다른 상태로 전이하는 규칙을 알아야 함.
43+
44+
### 상태 패턴 구현 방법
45+
46+
1. **누가 상태 전이를 정할 것인가?**
47+
상태 패턴은 상태 전이를 누가 책임져야 하는지 명시하지 않고 있음. 다만, 구체적 상태 클래스들이 자신 다음에 나오는 상태가 무엇이고 상태 전이가 언제 될지 결정하도록 만드는 것이 일반적으로 가장 유연하고 적절함.
48+
이 방식의 단점은 각 구체적 상태 클래스들이 다른 구체적 상태 클래스를 알아야 한다는 것. 즉, 서브클래스 사이의 구현 종속성이 생김.
49+
2. **상태 객체의 생성과 소멸**
50+
상태 객체를 필요할 때만 생성하고 필요 없게 되면 소멸시키는 방식과 필요하기 전에 모두 미리 만들어 두고 없애지 않고 계속 두는 방식 두가지가 있음.
51+
전자의 경우, 상태가 실행되기 전까지는 어떤 상태여야 하는지 모르거나 상태가 자주 바뀌지 않을 때 적합하고, 두 번째 방법은 상태 변화가 수시로 일어날 경우에 좋음. 이 방법의 단점은 Context 클래스가 언제나 모든 상태에 대한 참조자를 계속 관리해야 한다는 점.
52+
53+
### 상태 패턴의 장단점
54+
55+
#### 장점
56+
57+
1. **상태에 따른 행동을 국소화하고 서로 다른 상태에 대한 행동을 별도의 객체로 관리함.**
58+
상태 패턴을 사용하면, 한 상태에 관한 모든 행동을 하나의 객체로(단일 책임 원칙 SRP) 모을 수 있음. 즉, 새로운 상태와 전이 규칙, 그에 따른 행동이 필요해지면 다른 객체를 살펴볼 필요 없이 단순히 상태의 서브클래스를 추가로 정의하면 됨.(개방 폐쇄 원칙 OCP)
59+
2. **상태 전이를 명확하게 함.**
60+
어떤 객체가 자신의 현재 상태를 내부의 값으로만 가지면 상태 전이는 명확하게 표현할 수 없음. 그러나 상태별로 객체를 만들면 상태 전이가 눈에 보이게 됨. 또한, Context 클래스의 상태가 모호해지는 것을 막음. Context 클래스가 가지고 있던 `State` 필드의 인스턴스만 변경하는 것이 곧 상태 전이이기 때문에 단 하나의 상태만 가지고 있는 것이 보장됨.
61+
3. **거대한 조건 분기를 제거하여 핵심 비즈니스 로직의 가독성이 올라감.**
62+
상태 패턴을 사용하면 상태에 따른 서로 다른 동작을 위한 과도하게 길었던 `if`나 여러 조건 분기문이 사라지게 되고, 사용자가 직접 사용하게 되는 Context 클래스의 코드가 간결해짐. 그만큼 유지보수성이 증가함.
63+
64+
#### 단점
65+
66+
1. **프로그램에 상태가 얼마 없거나 상태가 거의 변하지 않는다면 오히려 과도한 작업이 될 수 있음.**
67+
상태 패턴은 자주 변화하는 여러 상태들을 객체화하여 Context 객체가 런타임 도중 스스로 상태를 바꿔가며 그에 맞는 행동을 할 수 있게 하는 것이 목적인데, 가지고 있는 상태가 적거나 거의 변하지 않는 프로그램에서는 오히려 불필요한 작업이 늘어나게 될 수 있음. (클래스를 새로 작성하는 것도 모두 추가적인 리소스를 필요로 한다.)
68+
69+
### 유사한 디자인 패턴
70+
71+
- 전략 패턴
72+
- 브리지 패턴
73+
- 어댑터 패턴
74+
75+
### 참고
76+
77+
- [Refactoring.Guru - State](https://refactoring.guru/ko/design-patterns/state)
78+
- GoF의 디자인 패턴 개정판 - Chapter 5 행동 패턴 상태(State)

0 commit comments

Comments
 (0)