상태 패턴
- 객체의 내부 상테에 따라 스스로 행동을 변경할 수 있게 허가하는 패턴으로, 이렇게 하면 객체는 마치 자신의 클래스를 바꾸는 것처럼 보인다.
활용성
- 객체의 행동이 상테에 띠라 달라질 수 있고, 객체의 상태에 따라서 런타임에 행동이 바뀌어야 합니다.
- 특정 연산에 그 객체의 상테에 따라 달라지는 다중 분기 조건 처리가 너무 많이 들어 있을 때, 객체의 상태를 표현하기 위해 상태를 하나 이상의 enum으로 정의해야 한다. 이때, 객체의 상태를 별도의 객체로 정의하면, 다른 객체들과 상관없이 그 객체의 상태를 댜양화시킬 수 있다.
구조
요소
- Context : 사용자가 관심 있는 인터페이스를 정의한다. 객체의 현재 상태를 정의한 ConcreteState 서브캘르스의 인스턴스를 유지, 관리한다.
- State : Context의 각 상태별로 필요한 행동을 캡슐화하여 인터페이스로 정의한다.
- ConcreteState : 서브클래스, 각 서브클래스들은 Context의 상태에 따라 처리되어야 할 실제 행동을 구현
협력 방법
- 요청을 받으면 Context는 ConcreteState에게 전달한다 ConcreteState는 State를 상속하는 서브클래스 중 하나의 인스턴스.
- Context는 실제 연산을 처리할 State 객체에 자신을 매개변수로 전달한다. 이로써 State 객체는 Context 클래스에 정의된 정보에 접근할 수 있다.
- Context는 사용자가 사용할 수 있는 기본 인터페이스를 제공한다. 사용자는 State 객체를 Context 객체와 연결시킨다. 이렇게 Context 객체를 만들고 나면 사용자는 State 객체를 직접 다루지 않고 Context에 요청만 보내면 된다.
장점
- 상태에 따른 행동을 국소화하며, 서로 다른 상태에 대한 행동을 별도의 객체로 관리한다.
- 새로운 상태가 생기면 새로운 클래스만 정의한다.
- 상태 전이를 명확하게 만든다.
- 상태 객체는 공유될 수 있다.
- State 객체는 인스턴스 변수 없이 여러 Context 클래스의 인스턴스로도 객체를 공유할 수 있다.
단점
예시 코드
protocol TCPState {
func transmit(_ connection: TCPConnection)
func activeOpen(_ connection: TCPConnection)
func close(_ connection: TCPConnection)
func changeState(_ connection: TCPConnection, _ state: TCPState)
}
extension TCPState {
func transmit(_ connection: TCPConnection) {
}
func activeOpen(_ connection: TCPConnection) {
}
func close(_ connection: TCPConnection) {
}
func changeState(_ connection: TCPConnection, _ state: TCPState) {
connection.setState(state)
}
}
protocol TCPConnection {
var state: TCPState { get set }
func setState(_ state: TCPState)
func transmit()
func activeOpen()
func close()
}
class TCPConnectionImplementation: TCPConnection {
var state: TCPState
init(initialState: TCPState) {
self.state = initialState
}
func setState(_ state: TCPState) {
self.state = state
}
func transmit() {
state.transmit(self)
}
func activeOpen() {
state.activeOpen(self)
}
func close() {
state.close(self)
}
}
struct TCPListen: TCPState {
func transmit(_ connection: TCPConnection) {
print("TCPListen: transmit 호출됨")
}
func activeOpen(_ connection: TCPConnection) {
print("TCPListen: activeOpen 호출됨")
}
func close(_ connection: TCPConnection) {
print("TCPListen: close 호출됨")
changeState(connection, TCPClosed())
}
}
struct TCPEstablished: TCPState {
func transmit(_ connection: TCPConnection) {
print("TCPEstablished: transmit 호출됨")
}
func activeOpen(_ connection: TCPConnection) {
print("TCPEstablished: activeOpen 호출됨")
}
func close(_ connection: TCPConnection) {
print("TCPEstablished: close 호출됨")
changeState(connection, TCPClosed())
}
}
struct TCPClosed: TCPState {
func transmit(_ connection: TCPConnection) {
print("TCPClosed: transmit 호출됨")
}
func activeOpen(_ connection: TCPConnection) {
print("TCPClosed: activeOpen 호출됨")
changeState(connection, TCPListen())
}
func close(_ connection: TCPConnection) {
print("TCPClosed: close 호출됨")
}
}
let connection = TCPConnectionImplementation(initialState: TCPListen())
connection.activeOpen()
connection.transmit()
connection.close()
참고