GoF์˜ ๋””์ž์ธ ํŒจํ„ด, ํ”„๋ก์‹œ ํŒจํ„ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณธ๋‹ค.

ํ•ด๋‹น ๊ธ€์€, ๋‹ค์Œ์˜ ์ฝ”๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์š”์•ฝ

  • Proxy: ๋Œ€๋ฆฌ์ธ
  • ์ž‘์—…์˜ ์‹คํ–‰์„ ๋Œ€๋ฆฌ์ธ์„ ํ†ตํ•ด ์‹คํ–‰ํ•˜๋„๋ก ํ•˜๋Š” ํŒจํ„ด
  • A๋ผ๋Š” ์ž‘์—…์„ B๋ผ๋Š” ๋Œ€๋ฆฌ์ธ์„ ํ†ตํ•ด ๋ณดํ†ต ์„ฑ๋Šฅ์  ์ด์ ์„ ์–ป๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
  • ์ด ๊ณผ์ •์—์„œ ์บ์‹ฑ์„ ํ†ตํ•ด ์ฒ˜๋ฆฌํ•œ๋‹ค๋ฉด ์บ์‹ฑ ํ”„๋ก์‹œ,
  • ๊ฐ€์ƒ์ ์œผ๋กœ ์„ฑ๋Šฅ์„ ๋†’ํ˜”๋‹ค๋ฉด ๊ฐ€์ƒ ํ”„๋ก์‹œ๋ผ ๋ถ€๋ฆ„
  • ํ•˜์ง€๋งŒ ํ•ต์‹ฌ์€, ๋Œ€๋ฆฌ์ธ์„ ํ†ตํ•ด ์–ด๋– ํ•œ ์ด์ ์„ ์–ป๊ณ  ์‹ถ์„ ๋•Œ, ์ด๋Ÿฌํ•œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋จ

๊ตฌ์กฐ

  • ScreenDisplay: ์–ด๋– ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๋Š” ๊ฐœ์ฒด
    • ๋ฐ์ดํ„ฐ๋ฅผ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๊ธฐ ๊นŒ์ง€ ๋Œ€๊ธฐ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค๊ณ  ๊ฐ€์ •
  • BufferDisplay: ScreenDisplay์˜ ์—ญํ• ์„ ๋Œ€์ฒดํ•˜์—ฌ ์–ด๋– ํ•œ ์ด์ ์„ ์–ป๊ธฐ ์œ„ํ•ด ๋งŒ๋“  Proxy
    • ScreenDisplay ๊ฐœ์ฒด๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ๊ฐ€์ง€๊ณ ์„œ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์„ฑ๋Šฅ์„ ๋†’ํž˜ - โ€œ๊ฐ€์ƒโ€ ํ”„๋ก์‹œ
  • Display: ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ํ•จ์ˆ˜ ์ธํ„ฐํŽ˜์ด์Šค
    • ํ•˜๋‚˜์˜ ํƒ€์ž…์œผ๋กœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

์‹œ๊ฐ„์ด ์˜ค๋ž˜๊ฑธ๋ฆฌ๋Š” ๊ฒฝ์šฐ ์˜ˆ

main

//
//  main.swift
//  Proxy
//
//  Created by Choiwansik on 2023/01/10.
//
 
import Foundation
 
internal func main() {
    let display = ScreenDisplay()
 
    display.print(content: "์•ˆ๋…•")
    display.print(content: "๋‚œ ์™„์ˆ™์ด์•ผ")
    display.print(content: "๋‚œ ๊ฐœ๋ฐœ์ž์•ผ")
    display.print(content: "๊ทผ๋ฐ ๋‚œ ๋ฐ˜์ˆ™์ด ๋” ์ข‹๋”๋ผ")
    display.print(content: "๊ณ„๋ž€์€ ํ›„๋ผ์ด๊ฐ€ ๋” ๋ง›์žˆ์–ด")
    display.print(content: "์Šคํฌ๋žจ๋ธ”์€ ๋ฒ„ํ„ฐ๋ฅผ ๊ผญ ๋นผ์ค˜")
    display.print(content: "๊ทธ๋Ÿผ ์•ˆ๋…•")
}
 
main()
 
 

Display

//
//  Display.swift
//  Proxy
//
//  Created by Choiwansik on 2023/01/10.
//
 
import Foundation
 
internal protocol Display {
    func print(content: String)
}
 

ScreenDisplay

//
//  ScreenDisplay.swift
//  Proxy
//
//  Created by Choiwansik on 2023/01/10.
//
 
import Foundation
 
internal class ScreenDisplay: Display {
 
    internal func print(content: String) {
        // content๋ผ๋Š” ๋ฌธ์ž์—ด์„ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋ ค๋ฉด ์ƒ๋‹นํ•œ ์‹œ๊ฐ„์ด ์†Œ์š”๋œ๋‹ค๊ณ  ๊ฐ€์ •
        Thread.sleep(forTimeInterval: 0.5)
 
        Swift.print(content)
    }
 
}
 

๊ฒฐ๊ณผ

์•ˆ๋…•
๋‚œ ์™„์ˆ™์ด์•ผ
๋‚œ ๊ฐœ๋ฐœ์ž์•ผ
๊ทผ๋ฐ ๋‚œ ๋ฐ˜์ˆ™์ด ๋” ์ข‹๋”๋ผ
๊ณ„๋ž€์€ ํ›„๋ผ์ด๊ฐ€ ๋” ๋ง›์žˆ์–ด
์Šคํฌ๋žจ๋ธ”์€ ๋ฒ„ํ„ฐ๋ฅผ ๊ผญ ๋นผ์ค˜
๊ทธ๋Ÿผ ์•ˆ๋…•
Program ended with exit code: 0
  • ํ•œ์ค„์”ฉ ์ฒœ์ฒœํžˆ ์ถœ๋ ฅ๋จ
  • ์ด๋Š” ScreenDisplay์˜ print(content:) ๋ฉ”์„œ๋“œ๊ฐ€ ์ถœ๋ ฅ์„ ์œ„ํ•ด ์ค€๋น„์‹œ๊ฐ„์ด ์˜ค๋ž˜๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ž„
  • ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ถœ๋ ฅํ•  ๋ฐ์ดํ„ฐ๋ฅผ ์ตœ๋Œ€ํ•œ ๋ชจ์•„์„œ print ๋ฉ”์„œ๋“œ๋ฅผ ์ตœ์†Œํ•œ์œผ๋กœ ํ˜ธ์ถœํ•ด์ฃผ๋ฉด ๋จ

Proxy๋ฅผ ํ†ตํ•œ ํ•ด๊ฒฐ

main

//
//  main.swift
//  Proxy
//
//  Created by Choiwansik on 2023/01/10.
//
 
import Foundation
 
internal func main() {
//    notUsingProxy()
    usingProxy()
}
 
internal func notUsingProxy() {
    let display: Display = ScreenDisplay()
 
    display.print(content: "์•ˆ๋…•")
    display.print(content: "๋‚œ ์™„์ˆ™์ด์•ผ")
    display.print(content: "๋‚œ ๊ฐœ๋ฐœ์ž์•ผ")
    display.print(content: "๊ทผ๋ฐ ๋‚œ ๋ฐ˜์ˆ™์ด ๋” ์ข‹๋”๋ผ")
    display.print(content: "๊ณ„๋ž€์€ ํ›„๋ผ์ด๊ฐ€ ๋” ๋ง›์žˆ์–ด")
    display.print(content: "์Šคํฌ๋žจ๋ธ”์€ ๋ฒ„ํ„ฐ๋ฅผ ๊ผญ ๋นผ์ค˜")
    display.print(content: "๊ทธ๋Ÿผ ์•ˆ๋…•")
}
 
internal func usingProxy() {
    let display: Display = BufferDisplay(bufferSize: 5)
 
    display.print(content: "์•ˆ๋…•")
    display.print(content: "๋‚œ ์™„์ˆ™์ด์•ผ")
    display.print(content: "๋‚œ ๊ฐœ๋ฐœ์ž์•ผ")
    display.print(content: "๊ทผ๋ฐ ๋‚œ ๋ฐ˜์ˆ™์ด ๋” ์ข‹๋”๋ผ")
    display.print(content: "๊ณ„๋ž€์€ ํ›„๋ผ์ด๊ฐ€ ๋” ๋ง›์žˆ์–ด")
    display.print(content: "์Šคํฌ๋žจ๋ธ”์€ ๋ฒ„ํ„ฐ๋ฅผ ๊ผญ ๋นผ์ค˜")
    display.print(content: "๊ทธ๋Ÿผ ์•ˆ๋…•")
 
    guard let bufferDisplay = display as? BufferDisplay else {
        return
    }
 
    bufferDisplay.flush()
}
 
main()
 
 

BufferDisplay

//
//  BufferDisplay.swift
//  Proxy
//
//  Created by Choiwansik on 2023/01/10.
//
 
import Foundation
 
internal class BufferDisplay: Display {
 
    internal init(bufferSize: Int) {
        self.bufferSize = bufferSize
    }
 
    internal func print(content: String) {
        self.buffer.append(content)
 
        if self.buffer.count == self.bufferSize {
            self.flush()
        }
    }
 
    internal func flush() {
        if self.screen == nil {
            self.screen = ScreenDisplay()
        }
 
        let lines = self.buffer.joined(separator: "\n")
        Swift.print(lines)
 
        self.buffer.removeAll()
    }
 
    private var buffer = [String]()
    private let bufferSize: Int
    private var screen: ScreenDisplay?
 
}
  • ScreenDisplay๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋Œ€๋ฆฌ์ž์ธ BufferProxy๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†๋„๋ฅผ ๋†’์ž„
  • ๋‹ค๋งŒ 5๊ฐœ์”ฉ ์ฒ˜๋ฆฌํ•œ๋‹ค๋Š” ์  ๋•Œ๋ฌธ์— ๋งˆ์ง€๋ง‰์— ๋ช…์‹œ์ ์œผ๋กœ flush๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ์–ด์•ผ ํ•จ

๋™๊ธฐ

  • ์บก์Šํ™”์˜ ๊ด€์ ์—์„œ ๋ณด์•˜์„ ๋•Œ, ๋‚ด๋ถ€ ๊ฐœ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์ดˆ๊ธฐํ™” ๊ฐ™์€ ๋ถ€๋ถ„์„ ํด๋ผ์ด์–ธํŠธ ์ชฝ์—์„œ๋Š” ๋ชจ๋ฅด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • ํ•˜์ง€๋งŒ ๊ฐ์ฒด ์ƒ์„ฑ๊ณผ ์ดˆ๊ธฐํ™”์— ์žˆ์–ด ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋œ๋‹ค๋ฉด, ํด๋ผ์ด์–ธํŠธ์—์„œ ์ด๋ฅผ ์ œ์–ดํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ๋‹ค.
    • ์‚ฌ์šฉํ•˜์ง€๋„ ์•Š๋Š” ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•ด๋‘๋Š” ๊ฒฝ์šฐ
  • ์ด๋Ÿด ๊ฒฝ์šฐ Proxy๋ผ๋Š” ๋Œ€๋ฆฌ์ธ ๊ฐœ์ฒด๋ฅผ ๋งŒ๋“ค์–ด, ๊ฐ์ฒด ์ƒ์„ฑ ํƒ€์ด๋ฐ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ฉด ์ง€์ €๋ถ„ํ•œ ์ฝ”๋“œ๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.
    • ๊ฐ์ฒด ์ƒ์„ฑ์˜ ์ฑ…์ž„์„ Proxy๊ฐ€ ๋‹ด๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์—.
  • ์˜ˆ๋ฅผ ๋“ค์–ด, ์ง์ ‘ ์ด๋ฏธ์ง€ ๋กœ๋“œ๋ฅผ ํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ณ ,
  • ์ค‘๊ฐ„์— ํ”„๋ก์‹œ ๊ฐœ์ฒด๋ฅผ ๋‘๊ณ , ์ด๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•จ์œผ๋กœ์จ ์‹ค์ œ ์‚ฌ์šฉ์‹œ์ ์„ ๋ช…ํ™•ํžˆ ํ•ด๋‘๋Š” ๊ฒƒ.

ํ™œ์šฉ์„ฑ

  • Remote Proxy
    • ์„œ๋กœ ๋‹ค๋ฅธ ์ฃผ์†Œ ๊ณต๊ฐ„์— ์กด์žฌํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€ํ‘œ ๊ฐ์ฒด๋กœ, ๋กœ์ปฌํ™˜๊ฒฝ์— ์œ„์น˜
    • ์•„๋งˆ ์ž์ฒด์ ์œผ๋กœ ๊ฐœ์ฒด๋ฅผ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์ธ ๋“ฏ ํ•จ
  • Virtual Proxy
    • imageProxy
    • ์š”์ฒญ์ด ์žˆ์„ ๊ฒฝ์šฐ์—๋งŒ ๊ณ ๋น„์šฉ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
    • ์บ์‹ฑ์ด ๋“ค์–ด๊ฐˆ ์ˆ˜๋„?
  • Protection Proxy
    • ์›๋ž˜ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์‹ค์ œ ์ ‘๊ทผ์„ ์ œ์–ด
    • ๊ฐ์ฒด๋ณ„๋กœ ์ ‘๊ทผ ์ œ์–ด ๊ถŒํ•œ์ด ๋‹ค๋ฅผ ๊ฒฝ์šฐ ์‚ฌ์šฉ
  • Smart reference(Smart Pointer)
    • ์ฐธ์กฐ ํšŸ์ˆ˜๋ฅผ ์ €์žฅํ•˜๋‹ค๊ฐ€ ๋”๋Š” ์ฐธ์กฐ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ๊ฐ์ฒด๋ฅผ ์ž๋™์œผ๋กœ ์—†์•ฐ
    • ์ฒ˜์Œ ์ฐธ์กฐ๋˜๋Š” ์‹œ์ ์— Persistence์—์„œ memory๋กœ ๋กœ๋“œํ•จ
    • ๊ฐ์ฒด ์ ‘๊ทผ ์ „์— ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ ‘๊ทผํ•  ๊ฒƒ์„ ๊ณ ๋ คํ•˜์—ฌ lock์„ ๊ฑบ

๊ฒฐ๊ณผ

  • ํ”„๋ก์‹œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด, ํŠน์ • ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ๋•Œ ์ถ”๊ฐ€์ ์ธ ํ†ต๋กœ๋ฅผ ์ œ๊ณตํ•˜๊ฒŒ ๋จ
  • ์ด ํ†ต๋กœ์—์„œ๋Š” ์–ด๋–ค ๋ชฉ์ ์„ ์ด๋ฃจ๋Š๋ƒ์— ๋”ฐ๋ผ ์ฑ…์ž„์„ ๊ฐ€์ง
    • ์›๊ฒฉ: ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ์ฃผ์†Œ ๊ณต๊ฐ„์— ์žˆ๋Š” ๊ฒƒ์„ ์ˆจ๊ธธ ์ˆ˜ ์žˆ์Œ
    • ๊ฐ€์ƒ: ๊ฐ์ฒด ์ƒ์„ฑ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ์˜ ์ตœ์ ํ™”
    • ๋ณดํ˜ธ/์Šค๋งˆํŠธ: ๊ฐ์ฒด ์ ‘๊ทผ์— ๋”ฐ๋ฅธ ์ถ”๊ฐ€์ ์ธ ๊ด€๋ฆฌ(๋ฉ”๋ชจ๋ฆฌ, ๊ถŒํ•œ, ์ƒ์„ฑ๊ณผ ์‚ญ์ œ)
  • Copy on write
    • ์‹ค์ œ ๋ณ€๊ฒฝ(ํ˜น์€ ์“ฐ๊ธฐ)๊ฐ€ ์ผ์–ด๋‚œ ๊ฒฝ์šฐ์—๋งŒ ๊ฐ’์„ ๋ณต์‚ฌํ•จ
    • ์ด๊ฑธ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด ์›๋ณธ์— ๋Œ€ํ•œ ์ฐธ์กฐ ๊ฐœ์ˆ˜๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•จ
      • ๋งŒ์•ฝ ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚ฌ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ
        1. ๋ณต์‚ฌ
        2. ์›๋ณธ์˜ ์ฐธ์กฐ ์นด์šดํŠธ -1
        3. ๋ณ€๊ฒฝ๋œ ๊ฐ’์„ ๊ฐ–๊ณ  ์‹ถ์€ ๋ณ€์ˆ˜์— 1๋ฒˆ ํ•ญ๋ชฉ์„ ํ• ๋‹น
    • ๊ฐ์ฒด์˜ ํฌ๊ธฐ๊ฐ€ ํฌ๋ฉด ํด์ˆ˜๋ก ํ•ด๋‹น ์ž‘์—…์€ ๋ณต์‚ฌ ๋น„์šฉ์„ ํ˜„๊ฒฉํ•˜๊ฒŒ ์ค„์—ฌ์คŒ

์ƒ๊ฐํ•ด๋ณผ ์ 

  • Copy on write๋Š” Proxy Pattern์ด๋‹ค.
  • Proxy๋Š” lazy, eager loading๊ณผ ๊ด€๋ จ์ด ์žˆ๋‹ค.
  • ๊ฐ ์ƒํ™ฉ์— ๋งž๋„๋ก ์ฒ˜๋ฆฌํ•ด์•ผ์ง€ ๋ฌด์กฐ๊ฑด์ ์œผ๋กœ ํ”„๋ก์‹œ ํŒจํ„ด์ด ์ข‹์€ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.
  • ํŒจํ„ด ์ž์ฒด๋ฅผ ์•„๋Š” ๊ฒƒ๋ณด๋‹ค, ๋ฌธ์ œ ์ƒํ™ฉ์ด ๋ฌด์—‡์ธ์ง€, ์–ด๋–ป๊ฒŒ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ˜„ ํ”„๋กœ์ ํŠธ์— ์ข‹์€์ง€๋ฅผ ๊ณ ๋ฏผํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

Reference