Jiseob Kim

iOS Developer

DesignPattern - Builder

12 Nov 2020 » DesignPattern


์˜ค๋žซ๋งŒ์— ๋ธ”๋กœ๊ทธ ๊ธ€ ๋‚จ๊ธฐ๊ธฐ.

์ฐธ๊ณ  ์„œ์ : gof์˜ ๋””์ž์ธ ํŒจํ„ด


๊ตฌ์„ฑ ์š”์†Œ

  • Builder
  • Concrete Builder
  • Director


Builder

Protocol


Concrete Builder

builder๋ฅผ ์ค€์ˆ˜ํ•œ ๊ตฌํ˜„ ํด๋ž˜์Šค


Director

Concrete Builder๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ return ํ•ด์ฃผ๋Š” ๊ตฌํ˜„ ํด๋ž˜์Šค



ํ•ต์‹ฌ = Builder

  • Builder๋Š” product๋ฅผ ์†์„ฑ ๊ฐ’์„ ์…‹ํŒ…ํ•˜๋Š” ํ•จ์ˆ˜๋Š” builder๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. (Chain์„ ์“ฐ๊ธฐ ์œ„ํ•จ.)

  • ๋ฉ”์†Œ๋“œ ์ƒ์„ฑ์‹œ ๋ฌถ์„ ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์€ ๊ฐ™์ด ๋ฌถ๋Š”๋‹ค

    • ex) UIButton์— ํ…Œ๋‘๋ฆฌ๋ฅผ ๋งŒ๋“ค๋•Œ ๋ณดํ†ต Color์™€ Width๋Š” ๋‘˜๋‹ค ์ž…๋ ฅํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ ์ธ์ž๊ฐ’์— Color์™€ Width๋ฅผ ๋„ฃ์–ด ํ•˜๋‚˜๋กœ ๋ฌถ๋Š”๋‹ค.


์žฅ์ 

  • Rxswift๋•Œ์ฒ˜๋Ÿผ ์ฒด์ธ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜์—ฌ, ๊ฐ์ฒด ์ƒ์„ฑ๋•Œ ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ์„ ํ•œ ๋ผ์ธ(์ค„๋ฐ”๊ฟˆ์€ ๋‹น์—ฐ!)์œผ๋กœ ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•˜์—ฌ, ํ•ด๋‹น ์ฝ”๋“œ ๋ถ„์‚ฐ์ด ์ ๋‹ค.
  • ์œ„์˜ ์˜ˆ์‹œ์ฒ˜๋Ÿผ Bolder์˜ Width์™€ Color๋Š” ๋ณดํ†ต ๋ฌถ์–ด์„œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ์ฝ”๋“œ ๋ผ์ธ์ด ๋” ์ ์–ด์ง„๋‹ค.
  • product๋ฅผ ์ƒ์„ฑ์‹œ ๋ฏธ๋ฆฌ ๋ฐ›์€ ์†์„ฑ ๊ฐ’์„ ์ด์šฉํ•ด ํ•„์ˆ˜ ๊ฐ’์„ ๋ˆ„๋ฝ ํ–ˆ๋Š”์ง€ ์•ˆํ–ˆ๋Š”์ง€ ํ™•์ธ ๊ฐ€๋Šฅ.


๊ทธ๋Ÿฌ๋ฉด Director๋Š”?

๋ฐฐ์šฐ๋ฉด์„œ ๊ฐœ์ธ์ ์ธ ์ƒ๊ฐ์œผ๋ก , Builder์™€ Concrete Builder๋งŒ์œผ๋กœ ์‹œ์ž‘ ํ–ˆ์„ ๋“ฏํ•˜๋‹ค.

์ฒด์ธ ๊ธฐ๋Šฅ์„ ์“ฐ๋ฉฐ, ์ž๊ธฐ๊ฐ€ Builder์— ์ถ”์ƒํ™”ํ•œ๋Œ€๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ์ƒˆ๋กœ์šด ๊ฐ์ฒด ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•ด์กŒ์œผ๋ฉฐ,

ํ•˜๋‹จ์˜ ๋ฒ„ํŠผ๋“ค์ด๋ผ๋˜๊ฐ€ ํŠน์ • ๋ทฐ๋“ค์ด ์ƒ์„ฑํ•˜๋‹ค๋ณด๋ฉด ๋ถ„๋ช… ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ๋‚˜์˜ฌ๊ฒƒ์ด๋‹ค.

๊ทธ๋Ÿผ, ์ด๋Ÿฐ ๊ณตํ†ต์˜ Concrete Builder๋“ค์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค ๋Š๋ผ๊ณ  Builder๋ฅผ Returnํ•˜๋Š” class๋ฅผ ๋งŒ๋“ค๊ณ 

์ด๋ฆ„์„ Director๋ผ๊ณ  ๋ถ™์—ฌ์ค€๊ฒƒ ๊ฐ™๋‹ค๋Š” ๋Š๋‚Œ์„ ๋ฐ›์•˜๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ <



UML - Class Diagram


์œ„์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์œผ๋ฉฐ ๋ˆˆ์—ฌ๊ฒจ ๋ณผ ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค

  • build๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ๋Œ๋ ค์ค€๋‹ค.
  • ํ…Œ๋‘๋ฆฌ ์ ์šฉ์‹œ width์™€ color๋ฅผ ๊ฐ™์ด ๋ฐ›๋Š”๋‹ค


๊ทธ๋ฆฌ๊ณ , Director๋Š” ๋ฏธ๋ฆฌ ์ •์˜ํ•œ ๋ฒ„ํŠผ์˜ Builder๋ฅผ ์ค€์ˆ˜ํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ ํ•ด์ค€๋‹ค.



CODE


Builder & ConcreteBuilder

๋ฉ”์†Œ๋“œ๋“ค์ค‘ ์ผ๋ถ€๋งŒ ์ฝ”๋“œ๋กœ ๋ณด์ž

(ํ”„๋กœํ† ์ฝœ์€ ์œ„์— ๊ทธ๋ฆผ์œผ๋กœ ์ถฉ๋ถ„ํ•˜๋ฏ€๋กœ ์ฝ”๋“œ ์ƒ๋žต.)


class ButtonConcreteBuilder: ButtonBuilder {
    private var product = UIButton()

    ... ์ƒ๋žต
    // ํ…์ŠคํŠธ ์ž…๋ ฅ
    func setTitle(_ title: String) -> ButtonBuilder {
        self.product.setTitle(title, for: .normal)
        return self
    }

    // ํ…Œ๋‘๋ฆฌ ์ ์šฉ (์ปฌ๋Ÿฌ์™€ ํญ์„ ํ•œ๋ฒˆ์— ๋ฐ›์•„ ๋ณด๋‹ค ์‰ฝ๊ฒŒ ์ ์šฉ)
    func setBolder(color: UIColor, width: CGFloat) -> ButtonBuilder {
        self.product.layer.borderWidth = width
        self.product.layer.borderColor = color.cgColor
        return self
    }

    // ๊ฐ์ฒด ๋ฐ˜ํ™˜
    func build() -> UIButton? {
        return self.product
    }
}

๊ฐ„๋‹จ.


Director

class ButtonDirector {
    static func makeBottomButton() -> UIButton {
        let titleColor = UIColor(red: 1, green: 192/255, blue: 0, alpha: 1)
        let highLightColor = titleColor.withAlphaComponent(0.4)
        let bgColor = UIColor(red: 51/255, green: 59/255, blue: 67/255, alpha: 1)
        let font = UIFont.boldSystemFont(ofSize: 17)
        let radius: CGFloat = 8

        let screenFrame = UIScreen.main.bounds
        let screenSize = screenFrame.size
        let margin: CGFloat = 12.0
        let height: CGFloat = 45.0
        let size = CGSize(width: screenSize.width - (margin * 2), height: height)
        let point = CGPoint(x: margin, y: screenSize.height - height - (margin * 2))
        let frame = CGRect(origin: point, size: size)


      	// 1. Chain์„ ์ด์šฉํ•˜์—ฌ ๊ฐ’ ์…‹ํŒ…
        let builder = ButtonConcreteBuilder()
            .setBGColor(bgColor)
            .setTitleColor(titleColor)
            .setTitleHighlightedColor(highLightColor)
            .setFont(font)
            .setFrame(frame)
            .setRadius(radius)
            .setTitle("Bottom")

        return builder.build()
    }
}

Director๋„ ํ”„๋กœํ† ์ฝœ์„ ์ƒ์„ฑํ•˜์—ฌ ์ค€์ˆ˜ํ•˜๊ฒŒ ๋งŒ๋“ค๋ฉด ์ข‹๊ฒ ์ง€๋งŒ? ์–˜๋Š” ์ผ๋‹จ ์ด๋ ‡๊ฒŒ ํ•ฉ์‹œ๋‹ค. ๋‚ด๊ฐ€ ํ•„์š”ํ•œ๊ฑด ๊ณตํ†ต์ ์œผ๋กœ ํ•˜๋‹จ์—์„œ ์“ฐ์ผ ๋ฒ„ํŠผ์ด๋‹ˆ๊น!


์—ฌ๊ธฐ์„œ ๋ˆˆ ์—ฌ๊ฒจ ๋ณด์•„์•ผํ•  ๊ฒƒ์€ ์ฃผ์„ ๋ถ€๋ถ„์ด๋‹ค.

์ฒด์ธ์„ ์ด์šฉํ•˜์—ฌ ์—ฐ๋‹ฌ์•„์„œ ๊ฐ’์„ ์ ์šฉ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ถ„์‚ฐ์ด ์•ˆ๋จ์„ ๋Š๋‚„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.


๊ทธ๋ฆฌ๊ณ  ๋งˆ๋ฌด๋ฆฌ๋ก  build()ํ•˜์—ฌ ๋ฒ„ํŠผ ๊ฐ์ฒด ๋ฐ˜ํ™˜.



์‚ฌ์šฉ

class ViewController: UIViewController {
		
    ...
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.addBottomButton()
    }
    
    private func addBottomButton() {
        let bottomButton = ButtonDirector.makeBottomButton()
        self.view.addSubview(bottomButton)
    }
}

์œ„์™€ ๊ฐ™์ด ์•„์ฃผ ๊ฐ„๋‹จํ•˜๊ฒŒ Director๋ฅผ ํ†ตํ•ด ํ™”๋ฉด์— ๋ฒ„ํŠผ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.




ํ•œ์ค„ํ‰


Builder ํŒจํ„ด์€ ๋ช…ํ™•ํ•˜๊ณ  ํ†ต์ผ์„ฑ ์žˆ๊ฒŒ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฐ„๋‹จํ•œ ์ปดํฌ๋„ŒํŠธ์— ์ ๋‹นํ•œ ๋Š๋‚Œ.