A A
[Design Pattern] Prototype Pattern - ํ”„๋กœํ† ํƒ€์ž… ํŒจํ„ด

Prototype Pattern

๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ๋ฏธ๋ฆฌ ์ •์˜๋œ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋ณต์ œ(clone)ํ•˜์—ฌ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค

  • ์•„๋ž˜์˜ ๊ฒฝ์šฐ ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณต์‚ฌํ•ด์„œ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š”๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
    • ์ข…๋ฅ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์•„์„œ ํด๋ž˜์Šค๋กœ ์ •๋ฆฌ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
    • ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ์ด ์–ด๋ ค์šด ๊ฒฝ์šฐ
    • framework ์™€ ์ƒ์„ฑํ•˜๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ

์žฅ์ 

  • ๊ฐ์ฒด ์ƒ์„ฑ ๋น„์šฉ ์ ˆ๊ฐ: ๋ณต์ œ(clone) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ, ๊ฐ์ฒด๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋น„์šฉ์ด ์ ๊ฒŒ ๋“ญ๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด ์ดˆ๊ธฐํ™”์˜ ๋‹จ์ˆœํ™”: ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ณผ์ •์ด ๋ณต์žกํ•  ๊ฒฝ์šฐ, ๋ฏธ๋ฆฌ ์ดˆ๊ธฐํ™”๋œ ๊ฐ์ฒด๋ฅผ ๋ณต์ œํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋™์ ์ธ ๊ฐ์ฒด ์ƒ์„ฑ: ๋Ÿฐํƒ€์ž„์— ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋‹จ์ 

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

Example

  • ๋‚ด๋ถ€ property๋กœ ๋ˆˆ, ์ฝ”, ๋ชธ, ๊ผฌ๋ฆฌ ์ƒ‰๊น”, ์ด๋ฆ„์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ณ ์–‘์ด Class
class Cat:
    def __init__(self):
        self.color = None
        self.eye_color = None
        self.nose_color = None
        self.tail_color = None
        self.name = None
  • ๋ˆˆ, ์ฝ”, ๋ชธ, ๊ผฌ๋ฆฌ ์ƒ‰๊น” ๋ชจ๋‘ white์ด๋ฉฐ ์ด๋ฆ„์€ kitty์ธ ๊ณ ์–‘์ด
kitty = Cat()
kitty.color = "white"
kitty.eye_color = "white"
kitty.nose_color = "white"
kitty.tail_color = "white"
kitty.name = "Kitty"

 

  • ๋ˆˆ, ์ฝ”, ๋ชธ, ๊ผฌ๋ฆฌ ์ƒ‰๊น” ๋ชจ๋‘ white์ด๋ฉฐ ์ด๋ฆ„์€ nabi์ธ ๊ณ ์–‘์ด
nabi = Cat()
nabi.color = "white"
nabi.eye_color = "white"
nabi.nose_color = "white"
nabi.tail_color = "white"
nabi.name = "Nabi"

 

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

class Cat:
    def __init__(self):
        self.color = None
        self.eye_color = None
        self.nose_color = None
        self.tail_color = None
        self.name = None
    
    def clone(self):
        return copy.deepcopy(self)

kitty = Cat()
kitty.color = "white"
kitty.eye_color = "white"
kitty.nose_color = "white"
kitty.tail_color = "white"
kitty.name = "Kitty"

nabi = kitty.clone()
nabi.name = "Nabi"

  • ์ •์˜ํ•œ Cat class ์•ˆ์— ๋™์ผํ•œ ๊ณ ์–‘์ด๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋Š” Clone ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋‘ ๋ฒˆ์งธ ๊ณ ์–‘์ด property๋ฅผ ํ•˜๋‚˜์”ฉ ์ง€์ •ํ•  ํ•„์š”์—†์ด cloneํ•œ ๋‹ค์Œ nabi์ด๋ฆ„๋งŒ ์ง€์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • kitty → clone์„ ํ†ตํ•ด nabi ๋ฅผ ๋ณต์ œ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทผ๋ฐ, nabi = kitty ์‹์œผ๋กœ ๋ณต์‚ฌ๋งŒ ํ•  ๊ฒฝ์šฐ๋Š”?

  • Reference ๊ธฐ๋ฐ˜ ์–ธ์–ด๋Š” Object๊ฐ€ Reference๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์™€ ๊ฐ™์ด ๋ณต์‚ฌ๋งŒ ํ•  ๊ฒฝ์šฐ, ํ•˜๋‚˜์˜ Object๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” Reference๊ฐ€ 2๊ฐœ ์ƒ๊ธธ ๋ฟ์ž…๋‹ˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ deepcopy๋ฅผ ํ†ตํ•ด ๊ณ ์–‘์ด ์ „์ฒด๋ฅผ ๋ณต์‚ฌํ•ด ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.
Prototype design pattern์˜ ์˜๋„๋Š” object๊ฐ€ copy๋˜๊ธฐ ์ „๊นŒ์ง€ ์ƒํƒœ๋ฅผ prototype์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
import copy

class Cat:
    def __init__(self):
        self.color = None
        self.eye_color = None
        self.nose_color = None
        self.tail_color = None
        self.name = None
    
    def clone(self):
        return copy.deepcopy(self)

class BlackCat(Cat):
    def __init__(self):
        super().__init__()
        self.color = 'black'

class WhiteCat(Cat):
    def __init__(self):
        super().__init__()
        self.color = 'white'
  • ์—ฌ๊ธฐ์„œ Cat class๋Š” Base class์ž…๋‹ˆ๋‹ค.
  • BlackCat, WhiteCat class๋Š” Cat class๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ ๊ณ ์–‘์ด ๋ชธ ์ƒ‰๊น”๋งŒ ๊ฐ๊ฐ black, white๋กœ ์ดˆ๊ธฐํ™” ํ•ฉ๋‹ˆ๋‹ค.
black_cat = BlackCat()
  • black_cat์€ ๋ชธ ์ƒ‰๊น”๋งŒ ์ง€์ •๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
  • ๊ทธ ๋‹ค์Œ ์ฝ”, ๊ผฌ๋ฆฌ ์ƒ‰์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ง„ object๋ฅผ prototype์œผ๋กœ ์‚ฌ์šฉํ•ด์„œ kitty & nabi๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
kitty = black_cat.clone()
kitty.eye_color = "white"
kitty.name = 'kitty'

nabi = black_cat.clone()
nabi.eye_color = "blue"
nabi.name = 'nabi'
  • ์ฆ‰, kitty๋Š” black_cat์„ cloneํ›„, ๋ˆˆ ์ƒ‰๊น”, ์ด๋ฆ„์„ ์ง€์ •ํ•ด์„œ ๋ฏธ์™„์„ฑ๋œ prototpye object๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์›ํ•˜๋Š” kitty object๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด๋ƒ…๋‹ˆ๋‹ค. (nabi ๋˜ํ•œ ๋™์ผ)
์ค‘๊ฐ„ ๋‹จ๊ณ„์˜ object๋ฅผ prototype์œผ๋กœ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ deepcopyํ•ด์„œ object๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋Š” ๋””์ž์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

Prototype์˜ ํ•ต์‹ฌ ๊ฐœ๋… 

  • Prototype(์›ํ˜•)์˜ ์—ญํ• 
    • Prototype์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ConcretePrototpye (๊ตฌ์ฒด์ ์ธ ์›ํ˜•)์˜ ์—ญํ• 
    • ConcretePrototpye์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณต์‚ฌํ•ด์„œ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ธธ์ œ๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • Client(์ด์šฉ์ž)์˜ ์—ญํ• 
    • Client๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

 

 

Example

# prototype

from abc import *
class Product(metaclass=ABCMeta):
    @abstractmethod
    def use(self):
        pass
    @abstractmethod
    def clone(self):
        pass
# Concrete

class UnderlinePen(Product):

    def use(self, s:str)
        n = len(s)
        print(s)
        for i in range(n):
            print("~", end="")
        print()
    
    def clone(self):
        return copy.deepcopy(self)
# Concrete

class MessageBox(Product):

    def _init_(self, deco:str):
        self.deco = deco
    
    def use(self, s:str):
        n = len(s) + 4

        for i in range(n):
            print(self.deco, end="")
        print()
        print(self.deco, s, self.deco)
        for i in range(n):
            print(self.deco, end="")
        print()
    
    def clone(self):
        return copy.deepcopy(self)
# Manager

class Manager:
    def _init_(self):
        self.showcase = {"a":1}
    
    def register(self, name:str, proto:Product):
        self.showcase[name] = proto
    
    def create(self, protoname:str):
        p = self.showcase[protoname]
        return p.clone()
# Client

manager = Manager()
m1 = MessageBox("*")
m2 = MessageBox("#")
p1 = UnderlinePen()

manager.register("msg", m1)
manager.register("msg#", m2)
manager.register("pen", p1)
msg1 = manager.create("msg")
msg2 = manager.create("msg#")
pen = manager.create("pen")

word = "hello"
msg1.use(word)
word = "world"
msg2.use(word)
pen.use(word)