디자인패턴 - Observer pattern

어흥·2024년 5월 3일

Computer Science

목록 보기
11/28

정의

관찰 중인 객체에서 발생하는 이벤트를 여러 다른 객체에 알리는 메커니즘을 정의할 수 있는 디자인 패턴

Swift 사용 예

  • Combine 프레임워크 - Publisher
  • NotificationCenter

  • Subject (Publisher)
    • Observer들을 가지고 있으며 개수는 제한이 없습니다.
    • Observer들을 추가, 제거하는 인터페이스를 제공합니다.
  • Concrete Subject (Publisher)
    • Concrete Observer 객체의 상태를 저장합니다.
    • 상태가 변경되면 Observer(Subscriber)에게 알립니다.
  • Concrete Observer (Subscriber)
    • Concrete Subject (Publisher) 객체에 대한 참조를 유지합니다.
    • Subject(Publisher)의 상태와 일관성을 유지합니다.
    • 객체의 상태와 일관성을 유지하기 위해 update 인터페이스를 구현합니다.

언제 사용하면 될까?

  • 다른 객체의 상태가 변경될 때마다 어떤 행동을 하고 싶을 때
    • ViewController에 Observer(Subscriber)가 있고, Model에 Subject(Publisher)가 있는 MVC 패턴
      • Model은 ViewController의 타입에 대해 알 필요 없이 상태가 변경될 때마다 이를 ViewController에 전달가능

        → 여러 개의 ViewController가 하나의 Model의 변경사항 사용

    • 구독 서비스

장단점

장점

  • Open / Close 원칙을 준수하여 Subject(Publisher)의 코드를 수정하지 않고 새로운 Observer(Subscriber) 클래스를 추가 가능(반대도 가능)
  • 런타임에서 객체간 관계를 설정 가능

단점

  • Observer(Subscriber)에게 알림이 가는 순서는 보장하지 않음
  • Observer, Subject의 관계가 잘 정의되지 않으면 원하지 않는 동작이 발생 가능

구현

  1. Publisher 인터페이스 정의

    정의해야할 프로토콜

    • subscribe: 옵저버를 추가
    • unSubscribe: 옵저버를 제거
    • notify: 추가된 옵저버들에게 알림을 보냄
    // Subject(Publisher) Interface
    protocol Publisher {
        var observers: [Observer] { get set }
        func subscribe(observer: Observer)
        func unSubscribe(observer: Observer)
        func notify(message: String)
    }
  2. Observer(Subscriber) 프로토콜을 정의

    // Observer(Subscriber) Interface
    protocol Observer {
        var id: String { get set }
        func update(message: String)
    }
  3. Publisher 역할을 하는 Apple Store 클래스를 정의

    // Concrete Subject(Publisher)
    class AppleStore: Publisher {
        var observers: [Observer]
        
        init(observers: [Observer]) {
            self.observers = observers
        }
        
        func subscribe(observer: Observer) {
            self.observers.append(observer)
        }
        
        func unSubscribe(observer: Observer) {
            if let index = self.observers.firstIndex(where: { $0.id == observer.id }) {
                self.observers.remove(at: index)
            }
        }
        
        func notify(message: String) {
            for observer in observers {
                observer.update(message: message)
            }
        }
    }
  1. AppleStore의 알람을 수신할 Customer 클래스도 정의

    // Concrete Observer(Subscriber)
    class Customer: Observer {
        var id: String
        init(id: String) {
            self.id = id
        }
        func update(message: String) {
            print("\(id)\(message)수신\n")
        }
    }
  2. 구현

    let appleStore = AppleStore(observers: [])
    let pingu = Customer(id: "Pinggu")
    let pinga = Customer(id: "Pingga")
    let roby = Customer(id: "Roby")
    
    appleStore.subscribe(observer: pingu)
    appleStore.subscribe(observer: roby)
    
    appleStore.notify(message: "iPhone 재고 입고 ")
    
    appleStore.unSubscribe(observer: roby)
    appleStore.notify(message: "iPhone 재고 입고 ")

0개의 댓글