Prototype Pattern 이란?
- 종류가 너무 많아 클래스로 정리되지 않는 경우
- 클래스로부터 인스턴스 생성이 어려운 경우
- 프레임워크와 생성하는 인스턴스를 분리하고 싶은 경우
이런 경우 클래스로부터 인스턴스를 만드는 것이 아니라
인스턴스를 복사해서 새로운 인스턴스를 만드는 게 좋음.
프로토타입 패턴을 적용하기 위해서는 Clone()이라는걸 가지고 있어야한다.
자기 자신을 복사할 수 있도록!
그리고 구체적인 클래스 정의를 해서 원형의 프로토타입을 상속 받는다.
class Cat:
def __init__(self):
self.color = None
self.eye_color = None
self.nose_color = None
self.tail_color = None
self.name = None
kitty = Cat()
kitty.color = 'white'
kitty.eye_color = 'white'
kitty.nose_color = 'white'
kitty.tail_color = 'white'
kitty.name = 'kitty'
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 클래스 안에 Clone을 만들어 주고 nabi를 만들때 활용했다.
이러면 다른 고양이의 property를 하나씩 지정할 필요없이
clone 한 다음에 이름만 따로 지정해주면 된다.
Prototype 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 BlackCate(Cat):
def __init__(self):
super().__init__()
self.color = 'black'
class WhiteCate(Cat):
def __init__(self):
super().__init__()
self.color = 'white'
Cat 클래스는 Base(기본)클래스이고
BlackCat 과 WhiteCat 클래스는 Cat 클래스를 상속받아서 몸색깔만 초기화함.
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'
black_cat = BlackCat() #몸 색깔만 지정된 상태
black_cat.nose_color = 'pink'#코랑 꼬리색을 지정
black_cat.tail_color = 'green'
#이렇게 만들어진 객체를 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하고 속성들을 따로 지정해주고 있다.
-> 원하는 객체를 쉽게 만들어냄.
중간단계의 객체를 prototype으로 만들고 이를 deepcopy 해서 객체를 만들어가는 디자인 패턴임을 알 수있다
Prototype 패턴의 등장인물 정리
• Prototype(원형)의 역할
Prototype은 인스턴스를 복사하여 새로운 인스턴스를 만들기 위한 메소드를 결정
• ConcretePrototype (구체적인 원형)의 역할
ConcretePrototype은 인스턴스를 복사해서 새로운 인스턴스를 만드는 메소드를 길 제로 구현
• Client(이용자)의 역할
Client는 인스턴스를 복사하는 메소드를 이용해서 새로운 인스턴스를 만든다
#Example 2
#추상클래스
class Product(metaclass = ABCMeta):
#사용하는 함수
@abstractmethod
def use(self):
pass
#복제하는 함수
@abstractmethod
def clone(self):
pass
#Concreate 1
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)
#Concreate 2
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)
class Manager:
def __init__(self):
self.showcase = {"a":1} #prototype instance
def register(self, name:str, proto:Product):
self.showcase[name] = proto
def create(self, protoName):
p = self.showcase[protoName]
return p.clone()
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)
출력은 다음과 같다.