Search

프로토타입 (디자인 패턴)

프로토타입 패턴

정의
프로토타입 패턴은 기존 객체를 복제하여 새로운 객체를 생성하는 객체 생성 디자인 패턴입니다.
주요 목적
1.
객체 생성 비용 절감
2.
복잡한 객체의 효율적 생성
3.
객체 상태의 쉬운 복제
4.
서브클래싱 없이 다양한 객체 설정 생성
핵심 특징
1.
복제 프로세스 위임: 객체 자체에 복제 과정을 위임합니다.
2.
공통 인터페이스: 모든 프로토타입 객체에 대해 'clone' 메서드를 포함한 공통 인터페이스를 선언합니다.
3.
느슨한 결합: 구체적인 클래스에 의존하지 않고 객체 복제가 가능합니다.
4.
clone 메서드: 대부분 유사하게 구현되며, 새 객체 생성 후 기존 객체의 필드 값을 복사합니다.
5.
비공개 필드 복사: 같은 클래스 내에서 비공개 필드도 접근 및 복사가 가능합니다.
장점
1.
복잡한 객체 생성 과정을 단순화합니다.
2.
객체 생성 비용을 줄일 수 있습니다.
3.
런타임에 객체 구성을 동적으로 제어할 수 있습니다.
4.
서브클래싱의 대안으로 사용될 수 있습니다.
적용 시나리오
객체 생성 비용이 높은 경우
다양한 설정을 가진 유사한 객체가 필요한 경우
객체의 클래스를 런타임에 결정해야 하는 경우
주요 구성 요소
- 프로토타입 기초 구현
a.
프로토타입 인터페이스
객체 복제를 위한 메서드(주로 clone)를 선언
모든 복제 가능한 객체가 이 인터페이스를 구현
b.
구상 프로토타입 클래스
프로토타입 인터페이스를 구현
clone 메서드를 실제로 구현하여 객체 복제 로직 제공
필요한 경우 복잡한 복제 과정(연결된 객체 복제, 재귀 종속성 해결 등) 처리
c.
클라이언트
프로토타입 인터페이스를 통해 객체를 복제
작동 방식:
clone 메서드는 현재 클래스의 새 객체를 생성하고 원본 객체의 필드 값을 복사
대부분의 언어에서 같은 클래스 내의 private 필드도 접근 가능하여 복사 가능
프로토타입 레지스트리
- 프로토타입 레지스트리
자주 사용되는 프로토타입 객체들을 저장하고 쉽게 접근할 수 있게 하는 컨테이너
기본적으로 이름을 키로 사용하는 해시맵 형태로 구현 가능
필요에 따라 더 복잡한 검색 기준을 가진 레지스트리 구현 가능
1.
장점
객체 생성 로직을 중앙화하여 코드 중복 감소
런타임에 새로운 객체 타입 추가 가능
복잡한 객체를 더 쉽게 생성 가능
상속 대신 객체 구성을 사용하여 더 유연한 설계 가능
2.
사용 시나리오
객체 초기화가 복잡하거나 비용이 많이 드는 경우
객체의 다양한 변형을 동적으로 생성해야 하는 경우
클래스의 인스턴스 수를 줄이고 싶을 때
이처럼 프로토타입 패턴을 사용하면 객체 생성 과정을 단순화하고, 런타임에 객체의 타입을 결정할 수 있으며, 복잡한 객체 구조를 효율적으로 복제할 수 있습니다. 이는 특히 객체 생성 비용이 높거나 객체의 상태가 복잡한 시스템에서 유용합니다
- 구현
Shape 추상 기본 클래스:
clone 메서드를 추상 메서드로 정의합니다.
공통 속성 (x, y, color)을 정의합니다.
RectangleCircle 구체 클래스:
Shape를 상속받습니다.
clone 메서드를 구현하여 자신의 복사본을 반환합니다.
Application 클래스:
다양한 도형 객체를 생성하고 관리합니다.
business_logic 메서드에서 모든 도형의 복사본을 생성합니다.
클라이언트 코드:
Application 인스턴스를 생성하고 business_logic을 실행합니다.
원본 도형들과 복제된 도형들을 출력하여 복제가 제대로 이루어졌는지 확인합니다.
from abc import ABC, abstractmethod from copy import copy class Shape(ABC): def __init__(self, x: int = 0, y: int = 0, color: str = ""): self.x = x self.y = y self.color = color def __init__(self, source: 'Shape' = None): if source: self.x = source.x self.y = source.y self.color = source.color @abstractmethod def clone(self) -> 'Shape': pass class Rectangle(Shape): def __init__(self, source: 'Rectangle' = None): super().__init__(source) if source: self.width = source.width self.height = source.height else: self.width = 0 self.height = 0 def clone(self) -> 'Shape': return Rectangle(self) class Circle(Shape): def __init__(self, source: 'Circle' = None): super().__init__(source) if source: self.radius = source.radius else: self.radius = 0 def clone(self) -> 'Shape': return Circle(self) class Application: def __init__(self): self.shapes = [] circle = Circle() circle.x = 10 circle.y = 10 circle.radius = 20 self.shapes.append(circle) another_circle = circle.clone() self.shapes.append(another_circle) rectangle = Rectangle() rectangle.width = 10 rectangle.height = 20 self.shapes.append(rectangle) def business_logic(self): shapes_copy = [] for s in self.shapes: shapes_copy.append(s.clone()) if __name__ == "__main__": app = Application() app.business_logic() # 시연을 위한 코드 print("Original shapes:") for shape in app.shapes: print(f"Type: {type(shape).__name__}, x: {shape.x}, y: {shape.y}") print("\nCloned shapes:") shapes_copy = [shape.clone() for shape in app.shapes] for shape in shapes_copy: print(f"Type: {type(shape).__name__}, x: {shape.x}, y: {shape.y}")
Python
복사
참고로 추상 클래스를 동반하지 않고 직접 객체를 복제하는 경우에도 프로토 타입입니다
import copy class Address: def __init__(self, street_address, suite, city): self.street_address = street_address self.suite = suite self.city = city def __str__(self): return f'{self.street_address}, Suite {self.suite}, {self.city}' class Employee: def __init__(self, name, address): self.address = address self.name = name def __str__(self): return f'{self.name} works at {self.address}' class EmployeeFactory: main_office_employee = Employee('', Address('123 East Drive', 0, 'London')) aux_office_employee = Employee('', Address('123B East Drive', 0, 'London')) @staticmethod def __new_employee(proto, name, suite): result = copy.deepcopy(proto) result.name = name result.address.suite = suite return result @staticmethod def new_main_office_employee(name, suite): return EmployeeFactory.__new_employee( EmployeeFactory.main_office_employee, name, suite ) @staticmethod def new_aux_office_employee(name, suite): return EmployeeFactory.__new_employee( EmployeeFactory.aux_office_employee, name, suite ) JOHN = EmployeeFactory.new_main_office_employee('John', 101) JANE = EmployeeFactory.new_aux_office_employee('John', 600) print(JOHN) print(JANE)
Python
복사
__new_employee라는 private 메서드를 포함한 public method를 호출함으로써 각종 employee 클래스를 복제합니다.

참고