๊ธ€ ์ž‘์„ฑ์ž: ๊ฐœ๋ฐœํ•˜๋Š” ํ›ˆ์ด

์˜ต์ €๋ฒ„ ํŒจํ„ด (Observer Pattern)

https://en.wikipedia.org/wiki/Observer_pattern

 

์˜ค๋Š˜ ์ •๋ฆฌํ•  ๋””์ž์ธ ํŒจํ„ด์€ ์˜ต์ €๋ฒ„ ํŒจํ„ด์ž…๋‹ˆ๋‹ค! ์˜ต์ €๋ฒ„ ํŒจํ„ด์€ ํ–‰๋™ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜๋กœ ์–ด๋–ค ๊ฐ์ฒด์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๊ด€์ฐฐํ•˜๊ณ  ์žˆ๋Š” ๊ฐ์ฒด์—๊ฒŒ ์•Œ๋ฆฌ๋Š” ๋ฐฉ์‹์œผ๋กœ ์šด์˜๋˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ์•Œ๋ฆผ์˜ ์ฃผ์ฒด๊ฐ€ ๋˜๋Š” ๊ฐ์ฒด(Subject)๋Š” ์ž์‹ ์„ ๊ด€์ฐฐํ•˜๋Š” ๊ฐ์ฒด(Observer)๋“ค๊ณผ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ๋งบ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

์™œ ์จ์•ผํ• ๊นŒ?

์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ ๊ฐ•๋ ฅํ•จ์€ ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ ๋Š์Šจํ•˜๊ฒŒ ์—ฐ๊ฒฐ(Loose Coupling)๋œ๋‹ค๋Š” ์ ์— ์žˆ์Šต๋‹ˆ๋‹ค. ๋Š์Šจํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋œ๋‹ค๋Š” ๊ฒƒ์€ ๋‘ ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๋“ค ์‚ฌ์ด์˜ ๊ฒฐํ•ฉ๋„๊ฐ€ ๋‚ฎ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ณ , ์„œ๋กœ๊ฐ€ ์„œ๋กœ์— ๋Œ€ํ•œ ์ตœ์†Œํ•œ์˜ ์ •๋ณด๋งŒ์„ ๊ฐ€์ง€๊ณ  ์†Œํ†ตํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋งํ•ฉ๋‹ˆ๋‹ค. 

 

๋งŒ๋“ค์–ด๋ณด๊ธฐ

๊ฐ€์ƒ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ์—ฐ์˜ˆ์ธ๊ณผ ๊ทธ ์—ฐ์˜ˆ์ธ์„ ํŒ”๋กœ์šฐํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์žˆ๋‹ค๊ณ  ํ•˜๊ณ , ์—ฐ์˜ˆ์ธ์ด ์ƒˆ๋กœ์šด ๊ธ€์„ ์˜ฌ๋ ธ์„ ๋•Œ ํŒ”๋กœ์›Œ๋“ค์—๊ฒŒ ์ž๋™์œผ๋กœ ์•Œ๋ฆผ์ด ์ „์†ก๋˜๋Š” ์‹œ์Šคํ…œ์„ ๋งŒ๋“ ๋‹ค๊ณ  ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. 

 

๋จผ์ € ์—ฐ์˜ˆ์ธ๋ถ€ํ„ฐ ๋งŒ๋“ค์–ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฐ์˜ˆ์ธ์€ ๊ด€์ฐฐ์˜ ๋Œ€์ƒ์ด ๋˜๋Š” Subject์˜ ์—ญํ• ์„ ํ•˜๊ฒ ์ฃ ?

protocol Observable {
    func notify (post: String)
    func add(follower: Follower)
    func remove(follower: Follower)
}

class Celebrity: Observable {
    let name: String
    var followers: [Follower] = []
    
    init(name: String) {
        self.name = name
    }
    
    func notify(post: String) {
        for follower in followers {
            follower.update(post: post)
        }
    }
    
    func add(follower: Follower) {
        self.followers.append(follower)
    }
    
    func remove(follower: Follower) {
        guard let removeIndex = followers.firstIndex(where: { $0 === follower }) else { return }
        self.followers.remove(at: removeIndex)
    }
}

์—ฐ์˜ˆ์ธ ํด๋ž˜์Šค๋Š” Observable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ , ๋‚ด๋ถ€์— ์ž์‹ ์„ ํŒ”๋กœ์šฐ ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ๋ชฉ๋ก์„ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ Subject๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•ด์•ผํ•˜๋Š” ์„ธ ๊ฐ€์ง€ ์—ญํ• ์ด ์žˆ๋Š”๋ฐ์š”, ๊ด€์ฐฐ์ž ๋“ฑ๋ก, ๊ด€์ฐฐ์ž ์ œ๊ฑฐ, ์•Œ๋ฆผ ์ „๋‹ฌ ์ž…๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ์ˆœ์„œ๋Œ€๋กœ add, remove, notify ๋ฉ”์„œ๋“œ๋ฅผ Observable ํ”„๋กœํ† ์ฝœ์— ์„ ์–ธํ•˜๊ณ , ์ด๋ฅผ ์ฑ„ํƒํ•œ ์—ฐ์˜ˆ์ธ ํด๋ž˜์Šค์—์„œ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. 

 

์ด์ œ ์—ฐ์˜ˆ๋“ค์„ ํŒ”๋กœ์šฐํ•˜๋Š” ์œ ์ €๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

protocol Followable {
    func update (post: String)
}

class Follower: Followable {
    let name: String
    
    init(name: String) {
        self.name = name
    }
    
    func update(post: String) {
        print("\(name)์ž…๋‹ˆ๋‹ค! -> \(post)")
    }
}

Followable ํ”„๋กœํ† ์ฝœ์€ ๊ด€์ฐฐํ•˜๋Š” ๋Œ€์ƒ์ธ Subject๊ฐ€ ๊ด€์ฐฐ์ž๋“ค์—๊ฒŒ ์•Œ๋ฆผ์„ ๋ณด๋‚ผ ๋•Œ ์–ด๋–ค ๊ฒฝ๋กœ๋กœ ๋ณด๋‚ผ ๊ฒƒ์ธ์ง€๋ฅผ ์ •์˜ํ• ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ  ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” Subject๋กœ๋ถ€ํ„ฐ ๋ฌธ์ž์—ด์„ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋„๋ก update ๋ฉ”์„œ๋“œ๊ฐ€ ์„ ์–ธ๋˜์–ด ์žˆ๊ณ  ์ž์‹ ์˜ ์ด๋ฆ„์— ๋ฐ›์€ ์•Œ๋ฆผ์„ ํ•จ๊ป˜ ์ถœ๋ ฅํ•˜๋„๋ก ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. 

 

์—ฐ์˜ˆ์ธ ํด๋ž˜์Šค์—๋Š” ์ƒˆ๋กœ์šด ํŒ”๋กœ์›Œ๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์ด ํŒ”๋กœ์›Œ๋“ค์„ ์ถ”๊ฐ€ํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

let han = Celebrity(name: "ํ•œํ˜ธ์—ด")
han.add(follower: Follower(name: "์•ˆ์ค€ํ˜ธ"))
han.add(follower: Follower(name: "ํ™ฉ์žฅ์ˆ˜"))
han.add(follower: Follower(name: "์กฐ์„๋ด‰"))

๊ทธ๋ฆฌ๊ณ  ์—ฐ์˜ˆ์ธ์ด ๊ฒŒ์‹œ๊ธ€์„ ํ•˜๋‚˜ ์—…๋ฐ์ดํŠธ ํ•˜๋ฉด, ๋ชจ๋“  ํŒ”๋กœ์›Œ๋“ค์ด ์•Œ๋ฆผ์„ ๋ฐ›๊ฒŒ๋ฉ๋‹ˆ๋‹ค.

han.notify(post: "ํ˜ธ๋ž‘์ด ์—ด์ •, ํ˜ธ์—ด์ด์—์š”~")

// ์•ˆ์ค€ํ˜ธ์ž…๋‹ˆ๋‹ค! -> ํ˜ธ๋ž‘์ด ์—ด์ •, ํ˜ธ์—ด์ด์—์š”~
// ํ™ฉ์žฅ์ˆ˜์ž…๋‹ˆ๋‹ค! -> ํ˜ธ๋ž‘์ด ์—ด์ •, ํ˜ธ์—ด์ด์—์š”~
// ์กฐ์„๋ด‰์ž…๋‹ˆ๋‹ค! -> ํ˜ธ๋ž‘์ด ์—ด์ •, ํ˜ธ์—ด์ด์—์š”~

์™œ ์ข‹์€์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์–ด์š”..

์œ„ ์˜ˆ์ œ์—์„œ ์—ฐ์˜ˆ์ธ์ด ํ•œ๋ช…๋งŒ ์ถ”๊ฐ€๋˜์–ด๋„ ์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ ์œ ์šฉํ•จ์„ ๋Š๋‚„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

let park = Celebrity(name: "๋ฐ•๋ฒ”๊ตฌ")
let han = Celebrity(name: "ํ•œํ˜ธ์—ด")
let ahn = Follower(name: "์•ˆ์ค€ํ˜ธ")

han.add(follower: ahn)
han.add(follower: Follower(name: "ํ™ฉ์žฅ์ˆ˜"))
han.add(follower: Follower(name: "์กฐ์„๋ด‰"))
han.notify(post: "ํ˜ธ๋ž‘์ด ์—ด์ •, ํ˜ธ์—ด์ด์—์š”~")

park.add(follower: ahn)
park.notify(post: "DP ๋ณต๊ท€ ์•ˆํ•˜๋‹ˆ?")

// ์•ˆ์ค€ํ˜ธ์ž…๋‹ˆ๋‹ค! -> ํ˜ธ๋ž‘์ด ์—ด์ •, ํ˜ธ์—ด์ด์—์š”~
// ํ™ฉ์žฅ์ˆ˜์ž…๋‹ˆ๋‹ค! -> ํ˜ธ๋ž‘์ด ์—ด์ •, ํ˜ธ์—ด์ด์—์š”~
// ์กฐ์„๋ด‰์ž…๋‹ˆ๋‹ค! -> ํ˜ธ๋ž‘์ด ์—ด์ •, ํ˜ธ์—ด์ด์—์š”~
// ์•ˆ์ค€ํ˜ธ์ž…๋‹ˆ๋‹ค! -> DP ๋ณต๊ท€ ์•ˆํ•˜๋‹ˆ?

์ƒˆ๋กœ์šด Subject๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์ง€๋งŒ, Follower ๊ฐ์ฒด์—๋Š” ์ „ํ˜€ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ฐ์ฒด๋“ค ์‚ฌ์ด์˜ ์˜์กด์„ฑ์ด ๋‚ฎ์•„์ง€๊ณ  ๋Š์Šจํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ๋˜ํ•œ ์˜ต์ €๋ฒ„ ํŒจํ„ด์€ ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„ ์›์น™ ์ค‘ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™๊ณผ ๊ฐœ๋ฐฉ ํ์‡„ ์›์น™์„ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค. ์–ด๋–ค ๊ฐ์ฒด๋ฅผ ํŒ”๋กœ์šฐ ํ•˜๋Š” ๊ฒƒ์€ ๋ชจ๋‘ Followable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” ๊ฐ์ฒด์—๊ฒŒ ๋งก๊ฒจ์ ธ ์žˆ๊ณ , ์ด ํŒ”๋กœ์›Œ๋“ค์„ ๊ด€๋ฆฌํ•˜๋Š” ์ฑ…์ž„์€ ๋ชจ๋‘ Observable ๊ฐ์ฒด์—๊ฒŒ ๋งก๊ฒจ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, Subject์—๋Š” ๋‹ค๋ฅธ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ ๋„ Follower ๊ฐ์ฒด์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.