๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐ŸŽ iOS/Swift

[iOS]์˜ต์ €๋ฒ„ ํŒจํ„ด

์˜ต์ €๋ฒ„ ํŒจํ„ด์ด๋ž€?

Observer Pattern(์˜ต์ €๋ฒ„)์ด๋ž€ ๊ด€์ฐฐ ์ค‘์ธ ๊ฐ์ฒด์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ๊ฐ์ฒด์— ์•Œ๋ฆฌ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋””์ž์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. iOS์—์„œ๋Š” Swift 5.1 ๋ฒ„์ „๋ถ€ํ„ฐ Combine ํ”„๋ ˆ์ž„์›Œํฌ์— Publisher๊ฐ€ ์ถ”๊ฐ€๋˜์–ด ์ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ  NotificationCenter๋„ ๋น„์Šทํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

 

  • Subject (Publisher)
    • Observer๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ๊ฐœ์ˆ˜๋Š” ์ œํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.
    • Observer๋“ค์„ ์ถ”๊ฐ€, ์ œ๊ฑฐํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • Concrete Subject (Publisher)
    • Concrete Observer ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
    • ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด Observer(Subscriber)์—๊ฒŒ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.
  • Observer (Subscriber)
    • ๊ฐ์ฒด์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์•Œ๋ ค์•ผํ•˜๋Š” ๊ฐ์ฒด์— ๋Œ€ํ•œ Update ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
    • ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด 
  • Concrete Observer (Subscriber)
    • Concrete Subject (Publisher) ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
    • Subject(Publisher)์˜ ์ƒํƒœ์™€ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฐ์ฒด์˜ ์ƒํƒœ์™€ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด update ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์˜ต์ €๋ฒ„ ํŒจํ„ด์€ ์–ธ์ œ ์“ฐ๋‚˜์š”?

๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์–ด๋–ค ํ–‰๋™์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์˜ต์ €๋ฒ„ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํŒจํ„ด์€ iOS์—์„œ๋Š” ViewController์— Observer(Subscriber)๊ฐ€ ์žˆ๊ณ , Model์— Subject(Publisher)๊ฐ€ ์žˆ๋Š” MVC ํŒจํ„ด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Model์€ ViewController์˜ ํƒ€์ž…์— ๋Œ€ํ•ด ์•Œ ํ•„์š” ์—†์ด ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ด๋ฅผ ViewController์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ViewController๊ฐ€ ํ•˜๋‚˜์˜ Model์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

ํ˜„์‹ค์—์„œ ์˜ต์ €๋ฒ„ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ์ƒํ™ฉ์„ ์ดํ•ดํ•ด๋ณด์ž๋ฉด, ์• ํ”Œ ๋งค์žฅ์— ์•„์ดํฐ์ด ๋งค์ง„ ์ƒํƒœ๋ผ๊ณ  ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„์ดํฐ์ด ์ž…๊ณ ๋  ๋•Œ DB์˜ ๋ชจ๋“  ๊ณ ๊ฐ์—๊ฒŒ ์•„์ดํฐ ์ž…๊ณ  ์•Œ๋ฆผ์„ ์ฃผ๊ฒŒ ๋˜๋ฉด ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ๋Š” ์ข‹์€ ์•Œ๋ฆผ์ด์ง€๋งŒ ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ๋Š” ์ŠคํŒธ์ด ๋  ์ˆ˜ ์žˆ๊ฒ ์ฃ ? ๋”ฐ๋ผ์„œ ์•„์ดํฐ์ด ์ž…๊ณ ๋  ๋•Œ ์•Œ๋ฆผ์„ ๋ฐ›๊ณ  ์‹ถ์€ ๊ณ ๊ฐ์— ๋Œ€ํ•ด์„œ๋งŒ ํ•ด๋‹น ์•Œ๋ฆผ์„ ์ฃผ๋Š” ๋“ฑ์˜ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์š”. ์ด๋Ÿด ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์˜ต์ €๋ฒ„ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ ๊ฒฐ๊ณผ?

์žฅ์ 

  • Open / Close ์›์น™์„ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Subject(Publisher)์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด Observer(Subscriber) ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๊ทธ ๋ฐ˜๋Œ€๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋Ÿฐํƒ€์ž„์—์„œ ๊ฐ์ฒด๊ฐ„ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์ 

  • Observer(Subscriber)์—๊ฒŒ ์•Œ๋ฆผ์ด ๊ฐ€๋Š” ์ˆœ์„œ๋Š” ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • Observer, Subject์˜ ๊ด€๊ณ„๊ฐ€ ์ž˜ ์ •์˜๋˜์ง€ ์•Š์œผ๋ฉด ์›ํ•˜์ง€ ์•Š๋Š” ๋™์ž‘์ด ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์ œ

๊ทธ๋Ÿผ Observer Pattern์„ Swift ์–ธ์–ด๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Combine ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ NotificationCenter๋กœ ๊ตฌํ˜„ ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๊ทธ๋ƒฅ ์ง์ ‘ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•œ ๋ฒˆ ๊ตฌํ˜„ํ•ด๋ณผ๊ฒŒ์š”.

์•„๊นŒ ์• ํ”Œ ๋งค์žฅ์— ์•„์ดํฐ์ด ๋งค์ง„๋œ ์ƒํ™ฉ์„ ๊ตฌํ˜„ํ•ด๋ณด๋ฉด ์žฌ๋ฐŒ์„๊ฒƒ ๊ฐ™์œผ๋‹ˆ ๊ทธ ์ƒํ™ฉ์„ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋จผ์ € Subject(Publisher) ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

// Subject(Publisher) Interface
protocol Publisher {
    var observers: [Observer] { get set }
    func subscribe(observer: Observer)
    func unSubscribe(observer: Observer)
    func notify(message: String)
}

์˜ต์ €๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” subscribe, ์˜ต์ €๋ฒ„๋ฅผ ์ œ๊ฑฐํ•˜๋Š” unSubscribe, ์ถ”๊ฐ€๋œ ์˜ต์ €๋ฒ„๋“ค์—๊ฒŒ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” notify ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ ธ์•ผ ํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋’ค ์—ฌ๊ธฐ์„œ ์‚ฌ์šฉํ•˜๋Š” Observer ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•ด์ค๋‹ˆ๋‹ค.

// Observer(Subscriber) Interface
protocol Observer {
    var id: String { get set }
    func update(message: String)
}

 

๊ทธ๋Ÿผ ์ด์ œ 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)
        }
    }
}

๊ทธ๋ฆฌ๊ณ  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")
    }
}

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ Observer Pattern์„ ๋ชจ๋‘ ๊ตฌํ˜„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ž˜ ์ž‘๋™ํ•˜๋Š”์ง€ ์‹คํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

 

 

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด ์œ„์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

appleStore์˜ ์•Œ๋ฆผ์„ ๋ฐ›๋Š” Customer ๊ฐ์ฒด์ธ pingu, roby๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ  notify ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด 2๋ช…์˜ Customer ๊ฐ์ฒด์— ์ž˜ ์ „๋‹ฌ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋’ค roby๋ฅผ unSubscribe๋กœ ์ œ๊ฑฐํ•ด์ค€ ๋’ค notify ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด Pingu ๊ฐ์ฒด์—๋งŒ ์ „๋‹ฌ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

\

728x90
๋ฐ˜์‘ํ˜•