swift 디자인패턴 - State Pattern
상태를 객체로 나타내기
"상태에 따라 사용할 수 있는 기능들이 달라져야 할때 사용된다."
상태패턴은 객체 내부의 상태에 따라서 객체가 다른 행동을 할 수 있게 해주는 패턴이다.
즉, 객체의 상태만 변경해 주어도, 다른 행동을 하는 객체로 만들어 준다.
상태 패턴은 유한 상태 머신과도 밀접한 관련이 있다.
다만 조건문에 기반한 상태 머신의 단점은, 상태의 수와 상태에 따른 동작이 추가될 때에 크게 드러난다.
대부분의 메서드에서 굉장히 지저분한 조건문이 들어가게 된다.
하지만 상태 패턴은 가능한 모든 상태에 대해서 클래스로 추출하는 방법을 사용한다.
목표
상태패턴을 통해 상태를 객체로 나타내고 행동을 구현한다.
키워드
객체, 상태, 행동
예제 1
구조
1.context : 하나의 상태를 갖고 모든 동작은 State 객체에 위임하는 객체다.
2.State : 상태에 따른 필요한 기능(메서드)을 선언하는 추상 클래스 객체 이다.
3.ContreateState : State 객체를 상속받은 실제 클래스로서 상태에 따른 기능을 실제로 구현하는 객체다.
해당 객체의 기능을 통하여 전환하여야 하는 상태를 정할 수 있다.
import Foundation
///
protocol State {
func update(context:Context)
func handle1()
func handle2()
}
/// 상태 에 따른 기능 1
class ConcreteStateA : State {
private weak var context:Context?
func update(context: Context) {
self.context = context
}
func handle1() {
print("ConcreteStateA handle1 request 1 요청!")
context?.changeState(state: ConcreteStateB())
}
func handle2() {
print("ConcreteStateA handle2 request 2 요청!")
}
}
/// 상태에 따른 기능 2
class ConcreteStateB : State {
private weak var context:Context?
func update(context: Context) {
self.context = context
}
func handle1() {
print("ConcreteStateB handle1 request 1 요청!")
}
func handle2() {
print("ConcreteStateB handle2 request 2 요청!")
context?.changeState(state: ConcreteStateA())
}
}
class Context {
private var state:State
init(state:State) {
self.state = state
changeState(state: state)
}
func changeState(state:State){
self.state = state
self.state.update(context: self)
}
func request1() {
state.handle1()
}
func request2() {
state.handle2()
}
}
let context = Context(state: ConcreteStateA())
context.request1()
context.request1()
/*
ConcreteStateA handle1 request 1 요청!
ConcreteStateB handle1 request 1 요청!
*/
예제2
- Context
- Context는 Concrete State 객체 중 하나에 대한 참조를 저장하고 모든 State의 작업을 위임합니다.
- Context는 State Interface를 통해 State 객체와 통신합니다.
- State
- State의 메서드를 제공합니다.
- Concrete State
- State Interface에서 정의된 메서드들을 구체화합니다.
- Concrete State는 Context 객체를 역으로 참조 할 수도 있습니다. 이러한 참조를 통해 State가 Context에서 필요한 정보를 가지고 오고 State를 변화할 수 있습니다.
//: [Previous](@previous)
import Foundation
/// State
protocol State {
/// [!] 상태에 따라 달라지는 기능 선언
/// 홈버튼 클릭
func playBackground()
/// 앱아이콘 클릭
func playForeground()
/// 비디오 다운로드 클릭
func videoDownload()
}
/// Context
class YoutubeApp {
/// 상태 객체
var youtubePreminumState: State
init(subscribeState: State) {
self.youtubePreminumState = subscribeState
}
/// 상태 객체를 구독객체로 변경
func subscribe() {
print("\n [***] 유튜브 프리미엄 구독 시작 상태로 변경됨 ^^ \n")
self.youtubePreminumState = SubscribeState()
}
/// 상태객체를 구독 해제 객체로 변경
func unSubscribe() {
print("\n [***] 유튜브 프리미엄 구독해지 상태로 변경됨 ㅜㅜ \n")
self.youtubePreminumState = UnSubscribeState()
}
/// 홈버튼 클릭
func clickHomeButton(){
self.youtubePreminumState.playBackground()
}
/// 앱 아이콘 클릭
func clickAppIcon(){
self.youtubePreminumState.playForeground()
}
/// 영상 다운로드
func clickDownload(){
self.youtubePreminumState.videoDownload()
}
}
/// 구독 상태 클래스 - concrete State
/// [!] 상태에 따라 달라지는 기능 구현
class SubscribeState:State {
func playBackground() {
print("결제를 해서 백그라운드에서도 재생중")
}
func playForeground() {
print("영상 재생중")
}
func videoDownload() {
print("결제 해서 영상 다운로드 가능")
}
}
/// 구독해제 클래스 - concrete State
/// [!] 상태에 따라 달라지는 기능 구현
class UnSubscribeState:State {
func playBackground() {
print("결제를 안 해서 백그라운드에서도 재생 불가....")
}
func playForeground() {
print("영상 재생 중")
}
func videoDownload() {
print("결제를 안 해서 영상 다운로드 불가...")
}
}
let youtubeApp = YoutubeApp(subscribeState: UnSubscribeState())
youtubeApp.clickAppIcon()
youtubeApp.clickDownload()
youtubeApp.clickHomeButton()
/// 구독
youtubeApp.subscribe()
youtubeApp.clickAppIcon()
youtubeApp.clickDownload()
youtubeApp.clickHomeButton()
/// 구독해지
youtubeApp.unSubscribe()
youtubeApp.clickAppIcon()
youtubeApp.clickDownload()
youtubeApp.clickHomeButton()
/*
로그
영상 재생 중
결제를 안 해서 영상 다운로드 불가...
결제를 안 해서 백그라운드에서도 재생 불가....
[***] 유튜브 프리미엄 구독 시작 상태로 변경됨 ^^
영상 재생중
결제 해서 영상 다운로드 가능
결제를 해서 백그라운드에서도 재생중
[***] 유튜브 프리미엄 구독해지 상태로 변경됨 ㅜㅜ
영상 재생 중
결제를 안 해서 영상 다운로드 불가...
결제를 안 해서 백그라운드에서도 재생 불가....
*/
출처
https://github.com/billnjoyce/Lectures/blob/master/docs/design%20patterns/%5BSwift%5D%20State.pdf
'아이폰 개발 > 디자인 패턴' 카테고리의 다른 글
swift 디자인 패턴 - 전략패턴(스트래티지 패턴) (0) | 2022.11.02 |
---|---|
디자인 패턴 - solid 원칙 정리 1 (0) | 2022.11.02 |
swift 디자인패턴 - Strategy Pattern (0) | 2021.08.22 |
swift 디자인패턴 - Facade Pattern (0) | 2021.08.21 |
swift 디자인패턴 - Adapter Pattern (0) | 2021.08.21 |