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

๋ฐœํ–‰/๊ตฌ๋… ํŒจํ„ด (ํŽ์„ญ/pubsub ํŒจํ„ด์ด๋ผ๊ณ  ํ•˜๋”๋ผ..)

์ง€๋‚œ ํฌ์ŠคํŠธ์—์„œ ์˜ต์ €๋ฒ„ ํŒจํ„ด์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ดค๋Š”๋ฐ์š”, ์˜ต์ €๋ฒ„ ํŒจํ„ด๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ ๋” ์œ ์—ฐํ•œ ๊ตฌ์กฐ๋ฅผ ์ง€๋‚œ ํŽ/์„ญ ํŒจํ„ด์œผ๋กœ ๋ถˆ๋ฆฌ๋Š” ๋ฐœํ–‰/๊ตฌ๋… ํŒจํ„ด์„ ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์˜ต์ €๋ฒ„ ํŒจํ„ด๊ณผ ๋น„์Šทํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํฌ๊ฒŒ ์„ค๋ช…ํ•  ๋‚ด์šฉ์€ ์—†์–ด ๋ณด์—ฌ์š”! ์˜ต์ €๋ฒ„ ํŒจํ„ด์ด ์•„์ง ๋‚ฏ์„ค๋‹ค๋ฉด ์ด ํฌ์ŠคํŠธ๋ฅผ ๋จผ์ € ์ฝ์–ด์ฃผ์„ธ์š”!

์˜ต์ €๋ฒ„ ํŒจํ„ด๊ณผ ๋ฌด์—‡์ด ๋‹ค๋ฅธ๊ฐ€์š”?

์˜ต์ €๋ฒ„ ํŒจํ„ด์ฒ˜๋Ÿผ ํŽ์„ญ ํŒจํ„ด๋„ ์–ด๋–ค ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” Subject ๊ฐ์ฒด์™€, ๊ทธ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์•Œ๋ฆผ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด Subject๋ฅผ ๊ด€์ฐฐํ•˜๋Š” Observer ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ค‘๊ฐ„์— ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ธŒ๋กœ์ปค๊ฐ€ ์กด์žฌํ•œ๋‹ค๋Š” ์ ์—์„œ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ Subject๋Š” ์ž์‹ ์ด ์ง์ ‘ Observer๋“ค์„ ๋ฐ›์•„ ๊ด€๋ฆฌํ•˜๊ณ  ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์•Œ๋ฆผ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํŽ์„ญ ํŒจํ„ด์€ Subject๋Š” ์ด๋ฒคํŠธ ๋ธŒ๋กœ์ปค์—๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ๋ณด๋‚ด๊ณ , ์ด๋ฒคํŠธ ๋ธŒ๋กœ์ปค๊ฐ€ Observer ๋“ค์—๊ฒŒ ์•Œ๋ฆผ์„ ๋ณด๋‚ด์ค๋‹ˆ๋‹ค. ์ค‘๊ฐ„์— ํ•œ ๊ณ„์ธต์ด ๋” ์ƒ๊ธด ๊ฒƒ์ด์ฃ . 

 

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

์˜ต์ €๋ฒ„ ํŒจํ„ด์—์„œ ๋งŒ๋“ค์—ˆ๋˜ ์˜ˆ์ œ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

import Foundation

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

protocol Followable {
    func update (post: String)
}

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)
    }
}

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

์ด์ œ ์—ฐ์˜ˆ์ธ ๊ฐ์ฒด๋Š” ์ž์‹ ์ด ์ง์ ‘ ํŒ”๋กœ์›Œ๋“ค์—๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ๋ณด๋‚ด์ง€ ์•Š๊ณ  ์ค‘๊ฐ„ ๋ธŒ๋กœ์ปค ๊ฐ์ฒด์—๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ๋ณด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ์ˆ˜์ •ํ•˜๋ฉด ์ข‹์„๊นŒ์š”? 

 

์ค‘๊ฐ„ ๋ธŒ๋กœ์ปค๋ฅผ ๋จผ์ € ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๋ธŒ๋กœ์ปค๋Š” ์–ด๋–ค ์—ฐ์˜ˆ์ธ์— ๋Œ€ํ•œ ํŒ”๋กœ์šฐ ์ •๋ณด๋ฅผ ๋ชจ๋‘ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด์„œ ์—ฐ์˜ˆ๋“ค์—๊ฒŒ ์ƒˆ๋กœ์šด ํฌ์ŠคํŒ…์„ ๋ฐ›์•„ ํŒ”๋กœ์›Œ๋“ค์—๊ฒŒ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

class PostManager {
    var celebrities : [Celebrity : [Follower]] = [:]
    static let `default` = PostManager()
    private init () {}
    
    func add(follower: Follower, of celebrity: Celebrity) {
        if celebrities[celebrity] != nil{
            celebrities[celebrity]!.append(follower)
        } else {
            celebrities[celebrity] = [follower]
        }
    }
    
    func remove(follower: Follower, of celebrity: Celebrity) {
        if celebrities[celebrity] != nil {
            guard let removeIndex = celebrities[celebrity]?.firstIndex(where: { $0 === follower }) else { return }
            celebrities[celebrity]?.remove(at: removeIndex)
        }
    }
    
    func notify(post: String, toFollowersOf celebrity: Celebrity) {
        if celebrities[celebrity] != nil {
            for follower in celebrities[celebrity]! {
                follower.update(post: post)
            }
        }
    }
}

ํฌ์ŠคํŠธ ๋งค๋‹ˆ์ €๋Š” ์—ฐ์˜ˆ์ธ๊ณผ ํŒ”๋กœ์›Œ๋“ค์˜ ๋ชฉ๋ก์„ ๋งตํ•‘ํ•ด์„œ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ๋ถ€ํ„ฐ๋Š” ์—ฐ์˜ˆ์ธ์€ ์ž์‹ ์„ ๋ˆ„๊ฐ€ ํŒ”๋กœ์šฐ ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์ง์ ‘ ์•Œ ์ˆ˜ ์—†๊ณ , ์‹ฌ์ง€์–ด๋Š” ํŒ”๋กœ์›Œ๋“ค๋„ ์ž์‹ ์ด ๋ˆ„๊ตด ํŒ”๋กœ์šฐํ•˜๊ณ  ์žˆ๋Š”์ง€ ์ง์ ‘์ ์œผ๋กœ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

 

ํฌ์ŠคํŠธ ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๊ตฌ์กฐ๊ฐ€ ์กฐ๊ธˆ ๋ฐ”๋€Œ์–ด์•ผ ํ•˜๊ฒ ์ฃ ? ์ด๋ฏธ ์˜ต์ €๋ฒ„ ํŒจํ„ด์„ ํ†ตํ•ด ์ฑ…์ž„ ๋ถ„๋ฆฌ๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ๋˜์–ด์žˆ์–ด์„œ ์‚ฌ์‹ค ์ˆ˜์ •ํ•  ๋‚ด์šฉ์ด ๋งŽ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ์—ฐ์˜ˆ์ธ ๊ฐ์ฒด์—๊ฒŒ ๋งก๊ฒจ์ ธ ์žˆ๋˜ ํŒ”๋กœ์›Œ๋“ค์„ ๊ด€๋ฆฌํ•˜๊ณ  ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ์ฑ…์ž„์„ ํฌ์ŠคํŠธ ๋งค๋‹ˆ์ €๋กœ ๋„˜๊ธฐ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

class Celebrity: Hashable, Observable {
    let name: String
    var followers: [Follower] = []
    
    init(name: String) {
        self.name = name
    }
    
    func notify(post: String) {
        PostManager.default.notify(post: post, toFollowersOf: self)
    }
    
    func add(follower: Follower) {
        PostManager.default.add(follower: follower, of: self)
    }
    
    func remove(follower: Follower) {
        PostManager.default.remove(follower: follower, of: self)
    }
    
    static func == (lhs: Celebrity, rhs: Celebrity) -> Bool {
        lhs === rhs
    }
    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
    }
}

๋‚˜๋จธ์ง€ ์ฝ”๋“œ๋Š” ์ „ํ˜€ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์˜ต์ €๋ฒ„ ํŒจํ„ด ๋•Œ์™€ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ๊ณผ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

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์—์„œ ํ•˜๋˜ ์ž‘์—…์„ ์ค‘๊ฐ„ ๊ณ„์ธต์ธ ์ด๋ฒคํŠธ ๋ธŒ๋กœ์ปค์—๊ฒŒ ๋„˜๊ฒจ์ค€ ๊ฒƒ๋ฟ์ด์ฃ . 

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

PostManager.default.add(follower: ahn, of: han)
PostManager.default.add(follower: Follower(name: "ํ™ฉ์žฅ์ˆ˜"), of: han)
PostManager.default.add(follower: Follower(name: "์กฐ์„๋ด‰"), of: han)
PostManager.default.notify(post: "ํ˜ธ๋ž‘์ด ์—ด์ •, ํ˜ธ์—ด์ด์—์š”~", toFollowersOf: han)
PostManager.default.add(follower: ahn, of: park)
PostManager.default.notify(post: "DP ๋ณต๊ท€ ์•ˆํ•˜๋‹ˆ?", toFollowersOf: park)

๊ทธ๋ฆฌ๊ณ  ์ด๋ ‡๊ฒŒ ์ˆ˜์ •ํ•˜๋ฉด ํŒ”๋กœ์šฐ, ํŒ”๋กœ์ž‰, ์ด๋ฒคํŠธ ๋ฐœํ–‰๊นŒ์ง€ ๋ชจ๋‘ ์ค‘๊ฐ„ ๋ธŒ๋กœ์ปค์—๊ฒŒ ๋งก๊ธฐ๋Š” ๋” ๋ถ„๋ฆฌ๋œ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. 

๊ทธ๋ž˜์„œ ์™œ ์ข‹์€๊ฐ€์š”?

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

 

์Šค์œ„ํ”„ํŠธ์˜ NotificationCenter๊ฐ€ ํŽ/์„ญ ํŒจํ„ด๊ณผ ์œ ์‚ฌํ•œ ํ˜•ํƒœ์˜ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์กฐ๋งŒ๊ฐ„ ํ•œ ๋ฒˆ ์ •๋ฆฌํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!