apple/DesignPattern, Architecture

Swift 디자인패턴 State Pattern (상태 패턴)

lgvv 2022. 5. 30. 19:26

Swift 디자인패턴 State Pattern (상태 패턴)

 

State Pattern은 객체의 내부 상태에 따라 동작이 변경되도록 설계하는 행동 패턴. 

 

히스토리

  • 2022-05-30: 디자인 패턴 스터디 정리
  • 2024-11-27: 포스팅 글 재정리 및 조금 더 실용적인 예제 코드로 변경

state pattern에 대한 설명

 

 

State Pattern

상태 패턴을 사용하면 객체의 상태를 별도의 상태 클래스로 추상화하고, 객체는 자신의 상태를 바꾸면서 동작을 동적으로 변경할 수 있음

  • Context: 상태를 관리하고, 현재 상태에 따라 행동을 위임하는 클래스
  • State: 공통 인터페이스 또는 추상 클래스 정의 모든 Concrete 클래스는 해당 인터페이스 구현
  • Concrete State: State 인터페이스를 구현한 클래스로 상태별 고유 동작 저의

상태 패턴을 적용할 수 있는 상황

  • if - else 혹은 switch 문에서 처리하는 내부 구문이 길어질 경우 분리
  • 플레이어의 상태에 따라 각 상태를 런타임에 관리하고, 불필요한 상태에 대한 부작용을 막기 위함

상태 패턴 장점

  • 행동의 캡슐화: 상태별 동작은 개별 객체에 정의하여 코드 가독성과 유지 보수성 높임
  • 상태 전환의 유연성: 객체 내부 상태를 쉽게 변경하고, 새로운 상태를 추가하거나 수정하기 쉬움
  • 조건문 감소: if - else 및 switch를 제거하고 객체로 동작을 위임

상태 패턴 단점

  • 상태 객체 수 증가: 각 상태마다 별도의 객체를 만들어야 해서 클래스가 증가
  • 간단한 논리라면 오히려 더 복잡해질 수 있음
  • 구현에 따라 결합도가 높아질 수 있음

 

코드 예제

플레이어에서 상태를 관리하는 State를 분리하는 간단한 예제

  • 플레이어는 복잡해서 각 상태에 따라서 퍼널 로그 수집, 각 상태에 따른 별도의 정책을 적용 받을 수 있어서 상태 처리가 복잡
import SwiftUI
import Foundation

/// 상태 인터페이스
protocol PlayerState {
    var player: VideoPlayer { get }
    
    func play()
    func pause()
    func stop()
}

/// Context
final class VideoPlayer {
    private var state: PlayerState? = nil

    init() {}

    func setState(_ state: PlayerState) {
        self.state = state
    }

    func play() {
        state?.play()
    }
    
    func pause() {
        state?.pause()
    }
    
    func stop() {
        state?.stop()
    }
}

// MARK: - Concrete States

class PlayingState: PlayerState {
    var player: VideoPlayer

    init(player: VideoPlayer) {
        self.player = player
    }

    func play() {
        print("Already playing.")
    }

    func pause() {
        print("Pausing playback...")
        player.setState(PausedState(player: player))
    }

    func stop() {
        print("Stopping playback...")
        player.setState(StoppedState(player: player))
    }
}

class PausedState: PlayerState {
    var player: VideoPlayer

    init(player: VideoPlayer) {
        self.player = player
    }

    func play() {
        print("Resuming playback...")
        player.setState(PlayingState(player: player))
    }

    func pause() {
        print("Already paused.")
    }

    func stop() {
        print("Stopping playback...")
        player.setState(StoppedState(player: player))
    }
}

class StoppedState: PlayerState {
    var player: VideoPlayer

    init(player: VideoPlayer) {
        self.player = player
    }

    func play() {
        print("Starting playback...")
        player.setState(PlayingState(player: player))
    }

    func pause() {
        print("Cannot pause. Player is stopped.")
    }

    func stop() {
        print("Already stopped.")
    }
}

private struct ContentView: View {
    var body: some View {
        Button("Execute") {
            let player = VideoPlayer()
            player.setState(PlayingState(player: player))
            
            player.play()
            player.pause()
            player.stop()
            player.play()
             
        }
    }
}

#Preview {
    ContentView()
}

결과

 

 

 

 

(참고)

https://www.raywenderlich.com/books/design-patterns-by-tutorials/v3.0/chapters/15-state-pattern

 

Design Patterns by Tutorials, Chapter 15: State Pattern

The state pattern is a behavioral pattern that allows an object to change its behavior at runtime. It does so by changing its current state. "State" here means the set of data that describes how a given object should behave at a given time.

www.kodeco.com:443

https://refactoring.guru/ko/design-patterns/state

 

상태 패턴

/ 디자인 패턴들 / 행동 패턴 상태 패턴 다음 이름으로도 불립니다: State 의도 상태 패턴은 객체의 내부 상태가 변경될 때 해당 객체가 그의 행동을 변경할 수 있도록 하는 행동 디자인 패턴입니

refactoring.guru