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

์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด

The abstract factory pattern provides an interface of creating families of related or dependent objects without specifying their concrete classes.

์ด์ „ ํฌ์ŠคํŠธ์—์„œ ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด์•˜๋Š”๋ฐ์š”, ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์€ ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด๊ณผ ์•„์ฃผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋””์ž์ธ ํŒจํ„ด์˜ ์ฐจ์ด๋ฅผ ์ด์•ผ๊ธฐ ํ•œ๋‹ค๋ฉด ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด์€ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๊ณ , ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์€ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์–ด์š”.

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

 

ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด vs. ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด 

์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด์„ ์งง๊ฒŒ ์ •๋ฆฌํ•ด๋ณด๊ณ  ์–ด๋–ป๊ฒŒ ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์ด ๋‹ค๋ฅธ์ง€ ์ดํ•ดํ•ด๋ณผ๊ฒŒ์š”.

ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด์€ ํŒฉํ† ๋ฆฌ์˜ ์—ญํ• ์„ ํ•˜๋Š” Creator๊ฐ€ ์žˆ๊ณ , factoryMethod๋ฅผ ํ†ตํ•ด ์–ด๋–ค ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋„๋กํ•ฉ๋‹ˆ๋‹ค. ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด์—์„œ๋Š” ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋งŒ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ๋˜๋Š” ๋ชจ๋“œ Concrete Product๋“ค์ด ์„œ๋กœ ๋…๋ฆฝ์ ์ž…๋‹ˆ๋‹ค. 

์ด์ œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ฐ์ฒด๋ฅผ ํ•œ ๋ฒˆ์— ์ƒ์„ฑํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์„ ์ƒ๊ฐํ•ด๋ณผ๊ฒŒ์š”.

์ด๋ ‡๊ฒŒ ์–ด๋–ค UI๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ 4๊ฐœ์˜ ๊ฐ์ฒด ์ค‘ ๋‘ ๊ฐœ๋ฅผ ์„ ํƒํ•ด ์กฐํ•ฉํ•œ๋‹ค๊ณ  ํ•ด๋ณผ๊ฒŒ์š”. BlackView๋Š” ๋‹น์—ฐํžˆ YellowButton๊ณผ ์กฐํ•ฉ์ด ๋˜์–ด์•ผ ์‚ฌ์šฉ์„ฑ์ด ์ข‹์„ ๊ฒƒ์ด๊ณ , YellowView๋Š” BlackButton๊ณผ ์กฐํ•ฉ์ด ๋˜์–ด์•ผ ์‚ฌ์šฉ์„ฑ์ด ์ข‹๊ฒ ์ฃ . ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” BlackView์™€ BlackButton, YellowView์™€ YellowButton์ด ์‹ค์ˆ˜๋กœ๋ผ๋„ ์กฐํ•ฉ๋˜์ง€ ์•Š๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. 

ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํŒฉํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒ ์ฃ ?

์ด๋ ‡๊ฒŒ ๋ฒ„ํŠผ์„ ์ƒ์„ฑํ•˜๋Š” ํŒฉํ† ๋ฆฌ, ๋ทฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํŒฉํ† ๋ฆฌ๋ฅผ ๊ฐ๊ฐ ๋งŒ๋“ค์–ด์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ . ํ•˜์ง€๋งŒ ์ด ํŒฉํ† ๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ๋Š” ๋ฐ˜๋“œ์‹œ ๋…ธ๋ž€์ƒ‰+๊ฒ€์€์ƒ‰์ด ์กฐํ•ฉ๋˜๋„๋ก ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. 

์ด๋ ‡๊ฒŒ ์–ด๋–ค ๊ฐ์ฒด๋“ค์ด ์„œ๋กœ ์˜์กด์„ฑ์„ ๊ฐ€์ง€๊ฑฐ๋‚˜ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•  ๋•Œ, ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฒ„ํŠผ์„ ๋งŒ๋“œ๋Š” ํŒฉํ† ๋ฆฌ, ๋ทฐ๋ฅผ ๋งŒ๋“œ๋Š” ํŒฉํ† ๋ฆฌ๋ฅผ ๋”ฐ๋กœ ๋‘๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋…ธ๋ž€์ƒ‰ ๋ฒ„ํŠผ๊ณผ ๊ฒ€์€์ƒ‰ ๋ทฐ๋ฅผ ๋งŒ๋“œ๋Š” ํŒฉํ† ๋ฆฌ, ๊ทธ๋ฆฌ๊ณ  ๊ฒ€์€์ƒ‰ ๋ฒ„ํŠผ๊ณผ ๋…ธ๋ž€์ƒ‰ ๋ทฐ๋ฅผ ๋งŒ๋“œ๋Š” ํŒฉํ† ๋ฆฌ๋ฅผ ๋‘๋Š” ๊ฒƒ์ด์ฃ . ํฌ์ŠคํŠธ ๊ฐ€์žฅ ์ฒ˜์Œ์— ์ ์—ˆ๋˜ "families of related or dependent objects" ๊ฐ€ ์ด๋Ÿฐ ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

๋จผ์ € ButtonBoxFactory๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๊ณ  ๋‚ด๋ถ€์— ๋‘ ๊ฐœ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ๋Š” ๋ทฐ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ์˜ ์ธํ„ฐํŽ˜์ด์Šค, ๋ฒ„ํŠผ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค์ด์ฃ . 

์ด ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” DarkButtonBoxFactory๋Š” ๊ฒ€์€์ƒ‰ ๋ทฐ๋ฅผ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•˜๊ณ , ๋…ธ๋ž€์ƒ‰ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์ด์ œ๋Š” ์ด ํŒฉํ† ๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ ๋ฐ˜๋“œ์‹œ ๊ฒ€์€์ƒ‰ ๋ทฐ์™€ ๋…ธ๋ž€์ƒ‰ ๋ฒ„ํŠผ์˜ ์กฐํ•ฉ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ LightButtonBoxFactory๋Š” ๋…ธ๋ž€์ƒ‰ ๋ทฐ์™€ ๊ฒ€์€์ƒ‰ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ํŒฉํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ญ์ƒ ๋…ธ๋ž€์ƒ‰ ๋ทฐ์™€ ๊ฒ€์€์ƒ‰ ๋ฒ„ํŠผ์˜ ์กฐํ•ฉ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

๊ตฌํ˜„ํ•ด๋ณด๊ธฐ

์œ„ ์˜ˆ์‹œ๋ฅผ ๊ทธ๋Œ€๋กœ ๊ตฌํ˜„ํ•ด๋ณผ๊ฒŒ์š”. 

๋จผ์ € Product์ธ View, Button๊ณผ Concrete Product์ธ YellowView, BlackView, YellowButton, BlackButton์„ ๋งŒ๋“ค์–ด์ค์‹œ๋‹ค.

import Foundation

protocol View: CustomStringConvertible {
    var id: String { get set }
    var color: String { get set }
}

extension View {
    var description: String {
        return "type: view id: \(id) color \(color)"
    }
}

protocol Button: CustomStringConvertible {
    var id: String { get set }
    var color: String { get set }
}

extension Button {
    var description: String {
        return "type: button id: \(id) color \(color)"
    }
}

class YellowView: View {
    var id: String
    var color: String = "Yellow"
    
    init(id: String) {
        self.id = id
    }
}

class BlackView: View {
    var id: String
    var color: String = "Black"
    
    init(id: String) {
        self.id = id
    }
}

class YellowButton: Button {
    var id: String
    var color: String = "Yellow"
    
    init(id: String) {
        self.id = id
    }
}

class BlackButton: Button {
    var id: String
    var color: String = "Black"
    
    init(id: String) {
        self.id = id
    }
}

let blackButton = BlackButton(id: "bb")
let yellowButton = YellowButton(id: "yb")
let blackView = BlackView(id: "bv")
let yellowView = YellowView(id: "yv")

print("\(blackView)\n\(blackButton)\n\(yellowView)\n\(yellowButton)")

// type: view id: bv color Black
// type: button id: bb color Black
// type: view id: yv color Yellow
// type: button id: yb color Yellow
// Program ended with exit code: 0

๊ฐ„๋‹จํ•˜์ฃ ? ์—ฌ๊ธฐ์„œ ๊ฐ Concrete Product์— ๋Œ€ํ•œ ํŒฉํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด์ด ๋˜๊ณ , ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์€ ์„œ๋กœ ์—ฐ๊ด€๋œ ๋‹ค์ˆ˜์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํŒฉํ† ๋ฆฌ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. 

protocol ButtonBoxFactory {
    func createView() -> View
    func createButton() -> Button
}

class DarkButtonBoxFactory: ButtonBoxFactory {
    func createView() -> View {
        return BlackView(id: "bv")
    }
    
    func createButton() -> Button {
        return YellowButton(id: "yb")
    }
}

class LightButtonBoxFactory: ButtonBoxFactory {
    func createView() -> View {
        return YellowView(id: "yv")
    }
    
    func createButton() -> Button {
        return BlackButton(id: "bb")
    }
}

์ฒ˜์Œ ์„ค๊ณ„ํ–ˆ๋˜๋Œ€๋กœ ๋‘ ๊ฐœ์˜ ํŒฉํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค์—ˆ๊ณ , ๊ฐ ํŒฉํ† ๋ฆฌ์—์„œ ๋‹คํฌ๋ชจ๋“œ, ๋ผ์ดํŠธ๋ชจ๋“œ์— ๋งž๋Š” ๋ทฐ์™€ ๋ฒ„ํŠผ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ด์ œ ํด๋ผ์ด์–ธํŠธ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ถ”์ƒํŒฉํ† ๋ฆฌ ํŒจํ„ด์ด ์™œ ์œ ์šฉํ•œ์ง€ ์ง์ ‘ ๋Š๊ปด๋ณด์ฃ !

class ButtonBox {
    enum ColorTheme {
        case dark, light
    }
    
    private var colorTheme: ColorTheme
    private var buttonBoxFacotry: ButtonBoxFactory
    private var button: Button?
    private var view: View?
    
    init(colorTheme: ColorTheme) {
        self.colorTheme = colorTheme
        self.buttonBoxFacotry = colorTheme == .dark ? DarkButtonBoxFactory() : LightButtonBoxFactory()
        self.createButtonBox()
    }
    
    private func createButtonBox() {
        self.button = buttonBoxFacotry.createButton()
        self.view = buttonBoxFacotry.createView()
    }
    
    func change(colorTheme: ColorTheme) {
        self.colorTheme = colorTheme
        self.buttonBoxFacotry = colorTheme == .dark ? DarkButtonBoxFactory() : LightButtonBoxFactory()
        self.createButtonBox()
    }
    
    func printComponents() {
        print(self.view!)
        print(self.button!)
    }
}

ButtonBox๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์—ˆ๊ตฌ์š”, ์ธ์ž๋กœ ์ฃผ์–ด์ง€๋Š” ์ƒ‰์ƒ ํ…Œ๋งˆ ์ •๋ณด๋ฅผ ํ†ตํ•ด ํŒฉํ† ๋ฆฌ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. ButtonBox๋ฅผ ์œ„ํ•ด ํ•„์š”ํ•œ ๋‘ ๊ฐ์ฒด์ธ View์™€ Button์€ ์ƒ์„ฑ๋œ ํŒฉํ† ๋ฆฌ๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์–ด๋–ค ํ…Œ๋งˆ์—์„œ ์ƒ์„ฑํ•ด์•ผํ•˜๋Š” ๊ฐ์ฒด ๋‹ฌ๋ผ์ง„๋‹ค๋ฉด ButtonBox๊ฐ€ ์•„๋‹ˆ๋ผ ButtonBoxFactory๋กœ ์ฐพ์•„๊ฐ€ ๊ฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•ด์ฃผ๋ฉด ๋˜๊ฒ ์ฃ ? ๊ทธ๋ฆฌ๊ณ  change ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์„œ ์œ ์—ฐํ•˜๊ฒŒ ๋ชจ๋“œ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์‰ฝ๊ฒŒ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

var buttonBox = ButtonBox(colorTheme: .dark)
buttonBox.printComponents()

print("\n## Change Factory ##\n")

buttonBox.change(colorTheme: .light)
buttonBox.printComponents()

// type: view id: bv color Black
// type: button id: yb color Yellow
//
// ## Change Factory ##
//
// type: view id: yv color Yellow
// type: button id: bb color Black
// Program ended with exit code: 0

ButtonBox์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•  ๋•Œ๋„, ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฐ ํ…Œ๋งˆ์— ๋งž๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ์ž…ํ•ด์ค„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋งˆ๋ฌด๋ฆฌ

๊ฒฐ๊ตญ ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์ด ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ํŒจํ„ด์œผ๋กœ๋ถ€ํ„ฐ ๊ตฌ๋ณ„๋˜๋Š” ๊ฐ€์žฅ ํฐ ํŠน์ง•์€ ํ•œ ํŒฉํ† ๋ฆฌ์—์„œ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜(Product)์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ด ๊ฐ์ฒด๋“ค์ด ์„œ๋กœ ์—ฐ๊ด€๋˜์–ด ์žˆ๊ฑฐ๋‚˜ ์˜์กด์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹จ์ˆœํžˆ ์ƒ์„ฑ๊ณผ ์ฃผ์ž…์˜ ์—ญํ• ๋งŒ์„ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ฐ์ฒด๋“ค์„ ์—ญํ• ์— ๋”ฐ๋ผ ์‘์ง‘์‹œํ‚ค๋Š” ์—ญํ• ๋„ ํ•˜๊ณ ์žˆ๋Š” ๊ฒƒ์ด์ฃ . 

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

์˜ค๋Š˜๋„ ์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!