Prototype Pattern

Prototype 패턴은 복잡한 초기화 과정을 거친 객체를 새로 생성하는 대신 기존 인스턴스를 복제하는 방식으로 객체 생성을 추상화합니다. “Prototype” 인터페이스와 이를 구현한 “Concrete Prototype”, 그리고 “Client” 가 핵심 참여자이며, 클라이언트는 clone() 만 호출해 객체를 얻는다. 이로 인해 생성 방식이 은닉되고, 런타임에 동적 객체 구성, 깊은 복제 (deep clone), 프로토타입 관리 (registry) 등 고급 기능을 구현할 수 있다.

배경

프로토타입 패턴은 다음과 같은 배경에서 등장했다:

  1. 객체 생성 비용 문제
    복잡한 객체 초기화 과정에서 발생하는 성능 병목 현상을 해결하기 위해 등장했다. 특히 데이터베이스 연결, 파일 로딩, 복잡한 계산 등이 포함된 객체 생성 시 유용하다.

  2. 타입 의존성 제거
    객체를 생성하는 코드가 구체적인 클래스에 의존하지 않도록 하여 시스템의 결합도를 낮추고자 했다.

  3. 동적 객체 생성 요구
    런타임에 객체의 타입과 구성을 결정해야 하는 경우, 미리 정의된 프로토타입을 통해 유연한 객체 생성을 지원한다.

목적 및 필요성

주요 목적:

  1. 성능 최적화: 복잡한 초기화 과정을 건너뛰어 객체 생성 속도 향상
  2. 유연성 향상: 런타임에 다양한 객체 구성을 동적으로 생성
  3. 코드 간소화: 서브클래스 대신 프로토타입 복제로 변형 객체 생성
  4. 결합도 감소: 클라이언트가 구체적인 클래스를 알 필요 없음

적용 필요성:

핵심 개념

Prototype Pattern 은 기존 객체를 템플릿으로 사용하여 새로운 객체를 생성하는 생성 디자인 패턴이다. 이 패턴의 핵심은 new 연산자를 통한 직접적인 객체 생성 대신, 미리 만들어진 프로토타입 객체를 복제 (clone) 하여 새로운 인스턴스를 생성하는 것이다.

프로토타입 패턴의 핵심 개념들을 실무 구현과 연계하여 분석하면 다음과 같다:

  1. 객체 복제 메커니즘 (Object Cloning Mechanism)
    기존 객체의 상태와 속성을 그대로 복사하여 새로운 인스턴스를 생성하는 메커니즘이다. 실무에서는 clone() 메서드나 Object.create(), copy.deepcopy() 등을 통해 구현된다.

  2. 프로토타입 인터페이스 (Prototype Interface)
    복제 가능한 객체들이 구현해야 하는 공통 인터페이스이다. 실무에서는 일관된 복제 동작을 보장하기 위해 추상 클래스나 인터페이스로 정의된다.

  3. 프로토타입 레지스트리 (Prototype Registry)
    자주 사용되는 프로토타입 객체들을 관리하는 저장소이다. 실무에서는 HashMap, Dictionary 등의 자료구조를 사용하여 프로토타입을 키 - 값 쌍으로 관리한다.

  4. 복사 수준 제어 (Copy Depth Control)
    얕은 복사와 깊은 복사를 구분하여 객체의 참조 관계를 적절히 처리한다. 실무에서는 비즈니스 요구사항에 따라 복사 수준을 결정한다.

패턴의 본질

의도 (Intent)

프로토타입 객체를 복제 (clone) 하여 새로운 객체를 생성할 수 있도록 한다. 객체의 구체 클래스를 알 필요 없이 복사만으로 객체를 생성할 수 있다.

다른 이름 (Also Known As)

동기 (Motivation / Forces)

적용 가능성 (Applicability)

패턴이 해결하고자 하는 설계 문제

문제를 해결하기 위한 설계 구조와 관계

실무 구현 연관성

주요 기능 및 역할

핵심 기능:

  1. 객체 복제: 기존 객체의 상태를 새로운 객체로 복사
  2. 동적 생성: 런타임에 복제할 프로토타입 선택
  3. 상태 보존: 복잡한 내부 상태를 그대로 유지
  4. 독립성 보장: 복제된 객체는 원본과 독립적으로 동작

패턴의 역할:

특징

구조적 특징:

동작 특징:

핵심 원칙

설계 원칙 준수

  1. 개방 - 폐쇄 원칙 (OCP): 새로운 프로토타입 추가 시 기존 코드 수정 불필요
  2. 의존 역전 원칙 (DIP): 구체적인 클래스가 아닌 복제 인터페이스에 의존
  3. 단일 책임 원칙 (SRP): 각 프로토타입은 자신의 복제에만 책임
  4. 리스코프 치환 원칙 (LSP): 모든 프로토타입은 동일한 인터페이스로 사용 가능

패턴 관계

주요 원리

  1. 복제 기반 생성 원리
    새로운 객체를 생성할 때 클래스 생성자를 호출하는 대신, 기존 객체의 복제 메서드를 호출하여 동일한 상태를 가진 새 인스턴스를 생성한다.

  2. 인터페이스 추상화 원리
    모든 복제 가능한 객체는 공통된 프로토타입 인터페이스를 구현하여 일관된 복제 동작을 보장한다.

  3. 레지스트리 관리 원리
    자주 사용되는 프로토타입 객체들을 중앙화된 레지스트리에서 관리하여 효율적인 접근과 재사용을 지원한다.

패턴 적용의 결과와 트레이드오프

구조 및 아키텍처

classDiagram
    class PrototypeInterface {
        <<interface>>
        +clone() Object
    }
    
    class ConcretePrototypeA {
        -property1: String
        -property2: int
        +clone() ConcretePrototypeA
        +setProperty1(value: String)
        +getProperty1() String
    }
    
    class ConcretePrototypeB {
        -propertyX: boolean
        -propertyY: double
        +clone() ConcretePrototypeB
        +setPropertyX(value: boolean)
        +getPropertyX() boolean
    }
    
    class PrototypeRegistry {
        -prototypes: Map<String, PrototypeInterface>
        +registerPrototype(key: String, prototype: PrototypeInterface)
        +getPrototype(key: String) PrototypeInterface
        +removePrototype(key: String)
    }
    
    class Client {
        -registry: PrototypeRegistry
        +createObject(type: String) Object
    }

    PrototypeInterface <|-- ConcretePrototypeA
    PrototypeInterface <|-- ConcretePrototypeB
    Client --> PrototypeRegistry
    PrototypeRegistry --> PrototypeInterface

구성 요소

구분구성 요소기능역할특징
필수Prototype Interface복제 메서드 정의모든 프로토타입이 구현해야 할 계약 정의일관된 복제 동작 보장
Concrete Prototype실제 복제 구현구체적인 객체 타입의 복제 로직 제공클래스별 특화된 복제 방식 지원
Clone Method객체 복제 수행자신의 복사본 생성 및 반환얕은/깊은 복사 선택 가능
선택Prototype Registry프로토타입 관리프로토타입 저장, 검색, 관리중앙화된 프로토타입 관리
Client복제 요청 및 사용프로토타입을 통한 객체 생성 요청구체적인 클래스에 의존하지 않음
Prototype Manager고급 관리 기능프로토타입 생명주기 관리동적 로딩/언로딩 지원

작동 원리 및 방식

sequenceDiagram
    participant Client
    participant PrototypeRegistry
    participant ConcretePrototype
    participant ClonedObject

    Client->>PrototypeRegistry: getPrototype("key")
    PrototypeRegistry->>ConcretePrototype: return prototype
    Client->>ConcretePrototype: clone()
    ConcretePrototype->>ClonedObject: create copy
    ClonedObject->>Client: return cloned object
    Client->>ClonedObject: customize properties

작동 순서:

  1. 클라이언트가 프로토타입 레지스트리에서 원하는 프로토타입을 요청
  2. 레지스트리에서 해당 프로토타입 객체 반환
  3. 프로토타입의 clone() 메서드 호출
  4. 복제된 새로운 객체 생성 및 반환
  5. 클라이언트가 필요에 따라 복제된 객체 속성 수정

참여 클래스와 객체

참여자들 간의 상호작용 방식

구현 기법

구분기법명핵심 정의 및 설명구성 요소활용 시나리오 예시
기본 복제 방식단순 복제 (Simple Clone)clone() 또는 copy() 메서드를 통한 얕은 복제 구현- Cloneable / copy() - 얕은 복사 (Shallow Copy)- 게임에서 동일 적 캐릭터 복제 - 문서 레이아웃/템플릿 빠른 생성
복사 생성자 (Copy Constructor)복사 생성자를 통해 명시적 필드 복사 (깊은 복사 가능)- 동일 클래스 매개변수 생성자 - 내부 참조도 수동 복사 구현Employee, Address 등 깊은 복사 요구 객체 복제
고급 복제 방식깊은 복사 (Deep Copy)중첩된 참조 객체까지 모두 복사 (직렬화 또는 재귀적 수동 복사 사용)- 재귀 복사 또는 Serializable + Stream 사용- 설정 객체, 복잡한 객체 그래프 백업 ML 모델/환경 구성 복제
직렬화 기반 복제 (Serialization)객체를 직렬화 후 역직렬화하여 깊은 복사 구현- ObjectOutputStream / ObjectInputStreamJava, Python 등에서 객체를 완전한 상태로 백업하거나 전달해야 하는 상황
구조적/관리적 접근프로토타입 레지스트리복제 가능한 객체들을 Map/Dictionary 등에 등록하여 동적 복제 제공- Map<String, Prototype> - 등록/조회 메서드 포함- 문서 템플릿, UI 컴포넌트 유형 저장소 - 유저 정의 도형 복제 등
런타임 동적 등록/삭제런타임 중 프로토타입을 동적으로 관리하고, 필요 시 삭제·수정 가능- 동적 객체 생성 관리 도구 - Registry 확장- 플러그인 시스템, 워크플로우 디자인 툴에서 사용자 정의 복제 구성 요소 관리
패턴 결합형Builder 결합 복제복제된 객체의 특정 속성을 변경하여 새로운 객체를 유연하게 생성 (Builder 패턴과 결합)- toBuilder() 또는 .copyWith() 메서드 - Immutable + Fluent APIDatabaseConfig, API 설정, 옵션별 테스트 설정 등 다양한 파생 객체 필요 시
Factory 결합 복제Prototype + Factory 결합으로 전략적으로 객체 생성 방식을 선택AbstractFactory + PrototypeRegistry 구조GUI 구성 요소를 전략에 따라 선택 복제 생성 - 전략적 객체 조합 생성 필요 시 사용
** 언어 특화 지원**Python deepcopy 기반copy.deepcopy() 를 통한 깊은 복사, 동적 타입 언어에서 유용- copy 모듈 활용 - 커스텀 클래스에 __deepcopy__ 정의 가능Python 기반 앱에서 데이터 모델 복제 Jupyter/RAG 등 유사 객체 다중 활용

단순 복제 (Shallow Copy)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import copy

class Product:
    def __init__(self, name, tags):
        self.name = name
        self.tags = tags  # 리스트는 얕은 복사 시 공유됨

    def clone(self):
        return copy.copy(self)  # 얕은 복사

# 사용 예시
original = Product("Book", ["tech", "python"])
cloned = original.clone()
cloned.tags.append("ai")

print(original.tags)  # ['tech', 'python', 'ai'] - 얕은 복사의 특성
print(cloned.tags)    # 동일한 리스트 참조

깊은 복제 (Deep Copy)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import copy

class Product:
    def __init__(self, name, tags):
        self.name = name
        self.tags = tags  # 리스트 구조 등 포함

    def clone(self):
        return copy.deepcopy(self)  # 깊은 복사

# 사용 예시
original = Product("Laptop", ["electronics", "computing"])
cloned = original.clone()
cloned.tags.append("portable")

print(original.tags)  # ['electronics', 'computing']
print(cloned.tags)    # ['electronics', 'computing', 'portable']

프로토타입 레지스트리 기반

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import copy

class PrototypeRegistry:
    def __init__(self):
        self._prototypes = {}

    def register(self, name, prototype):
        self._prototypes[name] = prototype

    def unregister(self, name):
        del self._prototypes[name]

    def clone(self, name, **attrs):
        prototype = self._prototypes.get(name)
        if not prototype:
            raise ValueError(f"Prototype '{name}' not found")
        cloned = copy.deepcopy(prototype)
        cloned.__dict__.update(attrs)  # 선택적 속성 변경
        return cloned

# 프로토타입 정의
class Button:
    def __init__(self, label, color):
        self.label = label
        self.color = color

    def __str__(self):
        return f"Button(label={self.label}, color={self.color})"

# 사용 예시
registry = PrototypeRegistry()
registry.register("submit", Button("Submit", "blue"))
registry.register("cancel", Button("Cancel", "gray"))

btn1 = registry.clone("submit", color="green")
btn2 = registry.clone("cancel")

print(btn1)  # Button(label=Submit, color=green)
print(btn2)  # Button(label=Cancel, color=gray)

Builder 패턴과 결합한 복제

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Report:
    def __init__(self, title, author, pages):
        self.title = title
        self.author = author
        self.pages = pages

    def to_builder(self):
        return ReportBuilder(self)

    def __str__(self):
        return f"Report(title={self.title}, author={self.author}, pages={self.pages})"

class ReportBuilder:
    def __init__(self, prototype=None):
        if prototype:
            self.title = prototype.title
            self.author = prototype.author
            self.pages = list(prototype.pages)
        else:
            self.title = ""
            self.author = ""
            self.pages = []

    def set_title(self, title):
        self.title = title
        return self

    def set_author(self, author):
        self.author = author
        return self

    def add_page(self, content):
        self.pages.append(content)
        return self

    def build(self):
        return Report(self.title, self.author, self.pages)

# 사용 예시
original = Report("ML Report", "Alice", ["Intro", "Data", "Model"])
draft = original.to_builder().set_title("ML Report (Draft)").add_page("Conclusion").build()

print(original)  # 원본 보고서
print(draft)     # 일부 수정된 복제본

직렬화 기반 깊은 복사

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import pickle

class Document:
    def __init__(self, content, metadata):
        self.content = content
        self.metadata = metadata

    def deep_clone(self):
        return pickle.loads(pickle.dumps(self))

# 사용 예시
original_doc = Document("Text here", {"author": "Bob", "version": 1})
cloned_doc = original_doc.deep_clone()
cloned_doc.metadata["version"] = 2

print(original_doc.metadata)  # {'author': 'Bob', 'version': 1}
print(cloned_doc.metadata)    # {'author': 'Bob', 'version': 2}

Shallow vs. Deep Copy

항목Shallow Copy (얕은 복사)Deep Copy (깊은 복사)
복사 범위객체의 최상위 필드만 복사 (1 차 레벨만 새 객체로 복사됨)객체의 모든 중첩 참조 객체까지 재귀적으로 복사
참조 동작하위 객체 (리스트, 딕셔너리 등) 는 원본과 참조를 공유함 (변경 시 원본 영향 가능)하위 객체까지 모두 독립적 복제, 원본과 완전 분리된 객체 그래프 구성
메모리 사용량상대적으로 낮음, 기존 객체 참조를 재사용하기 때문참조 객체까지 새로 생성되므로 메모리 사용량이 증가
성능 (속도)매우 빠름, 참조 복사만 수행하기 때문느릴 수 있음, 깊이와 복잡도에 따라 비용이 커짐
구현 난이도낮음, copy.copy() 또는 Object.clone() 등 간단한 API 사용 가능높음, 재귀 복사 구현 또는 copy.deepcopy(), 직렬화 필요
변경 감지/추적참조 공유로 인해 사이드 이펙트 발생 가능성 존재, 디버깅 어려움독립된 객체이므로 사이드 이펙트 없이 변경 추적 용이
불변 객체에 적합대부분의 경우 불변 객체에는 충분함 (값 자체 복제 의미 없음)불변 객체에는 과도한 자원 낭비가 될 수 있음
가변 객체에 적합적합하지 않음. 참조 공유로 인해 예상치 못한 변경 가능참조가 분리되어 있어 복잡한 상태 변경이 필요한 경우 적합
실무 사용 예시- 설정 템플릿 복제 - 게임 오브젝트 풀링 - 불변 객체 처리- 백업/복원 기능 - 모델 파라미터 복제 - 사용자 정의 객체 그래프 처리
대표적 사용 기술copy.copy() (Python), super.clone() (Java), 얕은 dict/list 복사copy.deepcopy() (Python), 객체 직렬화/역직렬화 (Java/Python), 커스텀 복사 생성자 등 사용 가능

장점

분류항목설명설계/기술적 원인 또는 근거
성능 최적화객체 생성 비용 절감복잡한 초기화 로직 없이 기존 객체 복제를 통해 빠른 생성 가능clone() 기반 메커니즘
성능 향상데이터베이스 접근, I/O 또는 무거운 연산 없이 객체 인스턴스를 빠르게 복제 가능캐시형 객체 복제 전략
메모리 효율성메모리 오버헤드 최소화복제된 객체는 불필요한 초기화 리소스를 사용하지 않으며, 필요한 필드만 유지함초기화 중복 제거 및 상태 공유
설계 유연성런타임 유연성실행 중 프로토타입을 레지스트리에 등록/해제하여 다양한 객체 구성을 동적으로 처리 가능Prototype Registry 패턴 적용
다양한 설정 조합 관리다양한 파라미터 조합을 갖는 설정 객체들을 템플릿처럼 복제하며 관리 가능복제 기반 설정 매니지먼트
의존성 감소결합도 감소클라이언트는 clone() 메서드만 호출하면 되므로 구체 클래스 (ConcretePrototype) 에 의존하지 않음인터페이스 기반 설계
클라이언트와 클래스 분리구체적인 생성자 호출 없이 복제만으로 객체를 확보할 수 있으므로 모듈 간 의존성이 낮아짐생성 책임 캡슐화
캡슐화 이점초기화 로직 중앙 집중화복잡한 객체 생성 로직을 하나의 프로토타입에 집중시켜 유지보수성과 재사용성을 향상객체 생성 책임의 위임
클라이언트 코드 단순화클라이언트는 복제된 인스턴스를 사용하기만 하면 되므로 코드가 간결하고 명확해짐복잡성 은닉 (Encapsulation)

단점과 문제점 그리고 해결방안

단점

항목설명해결책
복제 구현 복잡성깊은 복사 구현 시 순환 참조나 복잡한 객체 그래프가 있는 경우 오류 발생 가능copy.deepcopy(), 직렬화/역직렬화, 복사 유틸리티 모듈 사용, 순환 참조 탐지 알고리즘 적용
프로토타입 관리 오버헤드많은 수의 프로토타입을 레지스트리에 등록 시 메모리/버전/일관성 관리가 복잡해짐Lazy Loading, 사용 빈도 기반 자동 정리, 프로토타입 풀링 (Pooling) 기법 활용
수정 시 부작용Shallow Copy 일 경우 공유된 참조 객체 수정 시 다른 인스턴스에도 영향을 줄 수 있음불변 객체 (Immutable) 설계, selective deep copy, 공유 최소화
메모리/성능 부담대형 객체 또는 복잡한 객체를 복제할 경우 메모리 사용량과 연산 비용이 높아질 수 있음Lazy clone, clone caching, 필요할 때만 복제 전략 (Deferred Cloning) 적용
클론 대상 사전 존재 필요Prototype 은 사전에 생성되어 있어야 하므로 미리 준비 비용이나 메모리 부담이 발생할 수 있음지연 등록 전략 (lazy registration), 초기화 시점 유도 제어
인터페이스 강제성 부족언어에 따라 clone 오버라이드 강제화가 되지 않아 구현 누락 가능성 존재복제 전용 인터페이스 설계 (Cloneable, Prototype), 추상 메서드 선언으로 강제화

단점은 패턴 그 자체의 구조나 설계 특성에서 기인하며, 설계상의 전략으로 보완이 가능함.

문제점

항목원인영향탐지 및 진단예방 방법해결 방법 및 기법
순환 참조 복제 실패객체 내부에 자기 자신을 참조하는 구조에서 deep copy 시 무한 재귀 발생앱 크래시, 스택 오버플로우, 메모리 고갈테스트 도중 오류 발생, 무한 루프 탐지memoization 기반 복제 전략 도입deepcopy(memo) 구현 또는 custom 복제 로직 추가
레지스트리 동기화 문제멀티스레드 환경에서 동시에 프로토타입 등록/삭제 시 레이스 컨디션 발생잘못된 객체 참조 반환, 예외 발생thread-safe 모니터링 도구, Lock 미사용 감지 도구thread-safe collection 사용 (dict, concurrent map)lock 적용, synchronized block 또는 weakref 활용
복제 불일치클래스마다 복제 방식이 달라 clone() 결과가 예측 불가능하거나 불완전클라이언트 오동작, 런타임 예외복제 결과 검증 로직, 단위 테스트표준화된 복제 인터페이스 정의 (clone(), copy())복제 정책 일관화, 표준 복제 유틸리티 클래스 제공
복제 누락 (하위 클래스 미구현)하위 클래스에서 부모의 clone() 메서드를 오버라이드하지 않고 그대로 사용예상 외 객체 반환 (부모 타입 반환), 기능 누락코드 리뷰, 타입 검사, 오버라이드 검사 도구 사용추상 메서드 강제 구현, IDE 에서 검사 룰 추가추상 클래스에 abstract clone() 선언, 리팩토링 도구 사용
메모리 누수사용되지 않는 prototype 이 계속 레지스트리에 남아 GC 되지 않음메모리 사용량 증가, 성능 저하메모리 프로파일링 도구, GC 로그 분석사용 빈도 기반 자동 삭제, 참조 약화 (WeakMap 등)주기적 GC 유도, TTL 기반 캐시, 레지스트리 청소기 자동화 스케줄러 구현
객체 상태 일관성 문제복제 시 필드 누락 또는 잘못된 초기값 설정으로 객체의 상태가 불완전로직 오류, 잘못된 결과 반환복제 후 값 비교, 상태 검증 메서드 추가생성자/복제자에서 상태 정합성 검증 포함객체 유효성 검사 메서드 (validate()), 테스트 커버리지 확보

문제점은 런타임 환경이나 동시성, 복잡도에 의해 운영 중 발생하는 이슈로, 테스트/모니터링/리팩토링을 통해 예방과 해결이 가능함.

도전 과제

카테고리도전 과제원인영향해결 방안 및 기법
복제 구현 복잡도깊은 복사의 구조적 복잡성중첩 객체와 참조 구조가 많은 경우, 재귀적 복제 구현 필요복제 누락, 테스트 실패, 데이터 무결성 오류- copy.deepcopy() 또는 직렬화 기반 복사 Copy Constructor 패턴 - 복사 유틸리티 클래스화
참조 일관성shallow copy 로 인한 상태 공유 문제참조 객체를 그대로 복사하여 복제 인스턴스 간 참조가 공유됨예기치 않은 상태 변경, 동기화 오류- 불변 객체 활용 selective deep copy 적용 - 공유 객체를 clone 시 분리 복사
순환 참조 복제무한 루프 발생A → B → A 등 순환 구조를 clone 할 경우 재귀 폭주스택 오버플로우, 메모리 고갈- memo dict 기반 deepcopy 구현 - 약한 참조 (weakref) 사용 - 순환 차단 플래그 활용
성능 및 메모리 부하대규모 객체 복제 시 리소스 과다 사용불필요한 깊은 복사, 대용량 데이터 필드 복제 등GC 부담 증가, OutOfMemory, 응답 지연Copy-on-Write 전략 Lazy CloningObject Pool 활용 - 복제 최소화 정책 수립
레지스트리 관리프로토타입 레지스트리 과도 확장다양한 유형을 한 곳에서 관리, 사용 종료 객체 미정리 등메모리 누수, 관리 복잡도, 동기화 문제- WeakMap, TTL 기반 자동 정리 - 사용 빈도 기반 캐시 정책 - 레지스트리 생명주기 관리 시스템 도입
동시성 문제멀티스레드 환경에서 clone race 발생레지스트리 접근 또는 객체 clone 시 동기화 미비잘못된 객체 반환, 상태 비일관성- ConcurrentHashMap, 동기화된 registry- 복제 구간에 락 (lock) 적용 - 불변 prototype 구조 설계
현대 프레임워크 호환성다양한 생성 전략과의 통합 문제Spring, DI 컨테이너, ORM 등은 다른 객체 생성 패러다임 제공프레임워크 내 생성·복제 방식과 충돌- 어댑터 패턴 도입 - 각 프레임워크 별 Prototype 구현체 별도 정의 DI 연동 인터페이스 설계
복제 정확도 확보복제 누락/과복제 등으로 불일치 발생하위 클래스에서 clone 오버라이드 누락, 복제 기준 불명확예기치 않은 타입/상태 반환, 테스트 실패- abstract clone() 강제화 - 복제 가이드라인 수립 - 단위 테스트/비교 테스트 자동화 도구 구축
상태 초기화 누락복제 시 상태 클린업 또는 변경 누락원본 상태를 그대로 따라가면서, 특정 필드만 초기화 필요상태 불일치, 잘못된 동작clone 후 후처리 함수 (after_clone()) 설계 - 상태 검증 메서드 추가 - 빌더 패턴 결합

분류에 따른 종류 및 유형

분류 기준유형특징사용 사례
복제 깊이얕은 복사 (Shallow Copy)참조만 복사, 빠른 성능불변 객체나 단순한 구조의 객체
깊은 복사 (Deep Copy)모든 객체를 재귀적 복사복잡한 중첩 구조를 가진 객체
지연 복사 (Lazy Copy)수정 시점에 실제 복사 수행메모리 효율성이 중요한 경우
관리 방식단순 프로토타입개별 객체의 직접적인 복제소규모 애플리케이션
레지스트리 기반중앙 집중식 프로토타입 관리다양한 프로토타입이 필요한 경우
계층적 관리프로토타입 간의 상속 구조 활용복잡한 객체 계층이 있는 시스템
구현 방식인터페이스 기반Cloneable 등의 표준 인터페이스 활용Java, C# 등의 객체지향 언어
프로토타입 기반언어 자체의 프로토타입 메커니즘 활용JavaScript 등의 프로토타입 기반 언어
함수형 기반불변 객체와 함수형 복사 활용함수형 프로그래밍 패러다임
적용 범위단일 객체개별 객체의 복제설정 객체, 템플릿 객체
객체 그래프연관된 객체들의 일괄 복제복합 문서, 게임 오브젝트
시스템 상태전체 시스템 상태의 스냅샷백업/복원, 실행 취소 기능

실무 사용 예시

분야적용 사례/시스템적용 목적/설명함께 사용하는 기술/패턴주요 효과
게임 개발몬스터, 캐릭터, 아이템 인스턴스 복제AI, 스탯, 무기 구성 등 복잡한 초기 설정을 복제하여 다양한 게임 오브젝트 생성Unity, 객체 풀링, 스폰 시스템대량 생성 시 성능 향상, 메모리 효율성 확보
문서 관리/편집기템플릿 기반 문서 복제문서 양식, 스타일, 기본 필드 등을 복제하여 새 문서 빠르게 생성템플릿 엔진, DB, 워크플로우반복 업무 감소, 일관된 문서 생성
웹/앱 UI 설계컴포넌트/위젯 복제공통 UI 구성 요소를 복제하여 다양한 변형 생성 및 재사용React, Flutter, Builder 패턴빠른 UI 확장, 재사용성 향상
시뮬레이션/수학 모델시뮬레이션 객체 복제복잡한 계산/시뮬레이션 모델을 복제하여 병렬 시뮬레이션 처리수학/물리 시뮬레이션 라이브러리, 멀티스레딩처리 속도 향상, 초기화 오버헤드 감소
AI/ML 시스템모델 구성 복제학습된 모델 또는 파이프라인 구성을 복제하여 다양한 환경에서 재사용딥러닝 프레임워크, 모델 직렬화실험/배포 효율화, 초기화 시간 절감
설정/환경 관리배포/설정 템플릿 복제운영/개발/테스트 환경 설정의 공통 템플릿 복제 후 일부 속성만 수정YAML, Terraform, CloudFormation설정 일관성 유지, 환경 간 전환 속도 향상
전자상거래상품 템플릿 복제유사한 옵션을 가진 상품을 빠르게 복제하여 등록상품 관리 시스템 (PIM), Catalog API상품 등록 시간 단축, 옵션 확장 용이
CAD/그래픽 도구도형/블록 복제복잡한 도형/모듈을 복제하여 위치, 속성만 변경해 다양한 레이아웃 구성AutoCAD, 디자인 툴반복 작업 감소, 설계 일관성 확보
테스트 자동화테스트 데이터 복제동일 구조의 다양한 mock/test 데이터를 복제하여 다양한 시나리오 테스트 수행테스트 프레임워크, Mock 객체 생성 도구테스트 범위 확대, 데이터 준비 시간 단축
업무 워크플로우템플릿 기반 업무 단계 복제전형화된 비즈니스 흐름을 템플릿으로 관리하고 필요한 단계만 수정BPMN, 워크플로우 엔진업무 흐름 표준화, 수정 편의성 향상
DB/Schema 관리테넌트별 스키마 복제기존 스키마를 기반으로 신규 테넌트 환경 구성RDBMS, Liquibase, Flyway멀티테넌시 환경 신속 구성, 표준화된 초기 구조 유지

활용 사례

사례 1: 그래픽 에디터 도형 복제

시스템 구성: 그래픽 에디터에서 다양한 도형 (원, 사각형, 삼각형 등) 을 복제하여 새로운 도형을 생성.

Workflow:

  1. 사용자가 도형을 선택
  2. 복제 버튼 클릭
  3. 프로토타입 패턴을 통해 동일한 도형이 생성됨

프로토타입 패턴의 역할: 도형 객체의 복제를 담당하여, 객체 생성 비용을 줄이고, 다양한 도형 설정을 효율적으로 관리.

차이점: 프로토타입 패턴이 없을 경우, 매번 새로운 객체를 생성하고 모든 속성을 다시 설정해야 하므로 비효율적.

코드 구현 예시시

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import copy
from abc import ABC, abstractmethod

# Prototype Interface
class Shape(ABC):
    @abstractmethod
    def clone(self):
        pass

    @abstractmethod
    def draw(self):
        pass


# 구체적인 Prototype: 원
class Circle(Shape):
    def __init__(self, x, y, radius, color):
        self.x = x
        self.y = y
        self.radius = radius
        self.color = color

    def clone(self):
        return copy.deepcopy(self)

    def draw(self):
        print(f"[Circle] 위치: ({self.x}, {self.y}), 반지름: {self.radius}, 색상: {self.color}")


# 구체적인 Prototype: 사각형
class Rectangle(Shape):
    def __init__(self, x, y, width, height, color):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color

    def clone(self):
        return copy.deepcopy(self)

    def draw(self):
        print(f"[Rectangle] 위치: ({self.x}, {self.y}), 크기: {self.width}x{self.height}, 색상: {self.color}")


# 클라이언트: 사용자 인터페이스 동작 시뮬레이션
def simulate_editor_clone():
    # 도형 객체 생성
    original_circle = Circle(100, 200, 50, "red")
    original_rectangle = Rectangle(50, 50, 150, 100, "blue")

    # 도형 복제 (Prototype 사용)
    cloned_circle = original_circle.clone()
    cloned_rectangle = original_rectangle.clone()

    # 복제된 도형의 속성 수정
    cloned_circle.x += 50
    cloned_circle.color = "green"

    cloned_rectangle.y += 30
    cloned_rectangle.color = "orange"

    # 결과 출력
    print("🎨 원본 도형:")
    original_circle.draw()
    original_rectangle.draw()

    print("\n🖨️ 복제된 도형:")
    cloned_circle.draw()
    cloned_rectangle.draw()


# 실행
simulate_editor_clone()

사례 2: 전자상거래 플랫폼의 상품 카탈로그 시스템

이 사례에서는 대규모 전자상거래 플랫폼에서 수백만 개의 상품 정보를 효율적으로 관리하기 위해 프로토타입 패턴을 활용.

시스템 구성:

graph TB
    Client[클라이언트 애플리케이션]
    ProductRegistry[상품 프로토타입 레지스트리]
    CategoryPrototype[카테고리별 프로토타입]
    ProductCache[상품 캐시]
    Database[(상품 데이터베이스)]
    
    Client --> ProductRegistry
    ProductRegistry --> CategoryPrototype
    CategoryPrototype --> ProductCache
    ProductCache --> Database

시스템 구성 설명:

Workflow:

  1. 시스템 초기화 시 카테고리별 대표 상품을 프로토타입으로 등록
  2. 새 상품 생성 요청 시 해당 카테고리 프로토타입을 복제
  3. 복제된 객체에 개별 상품 정보 설정
  4. 캐시 및 데이터베이스에 저장

프로토타입 패턴의 역할:

코드 구현 예시:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import copy

# 상품 클래스 정의
class Product:
    def __init__(self, name, category, price, tax_rate, shipping_policy, return_policy):
        self.name = name
        self.category = category
        self.price = price
        self.tax_rate = tax_rate
        self.shipping_policy = shipping_policy
        self.return_policy = return_policy

    def clone(self):
        return copy.deepcopy(self)

    def set_details(self, name, price):
        self.name = name
        self.price = price

    def __str__(self):
        return (f"상품명: {self.name}, 카테고리: {self.category}, 가격: {self.price}, "
                f"세금: {self.tax_rate}, 배송: {self.shipping_policy}, 반품: {self.return_policy}")


# 상품 프로토타입 레지스트리
class ProductRegistry:
    def __init__(self):
        self._prototypes = {}

    def register_prototype(self, category, prototype: Product):
        self._prototypes[category] = prototype

    def create_product(self, category, name, price):
        if category not in self._prototypes:
            raise ValueError(f"카테고리 '{category}'에 대한 프로토타입이 등록되지 않았습니다.")
        product = self._prototypes[category].clone()
        product.set_details(name, price)
        return product


# 초기 설정: 시스템 부팅 시 카테고리별 프로토타입 등록
def initialize_registry():
    registry = ProductRegistry()

    # 카테고리별 공통 설정 등록
    registry.register_prototype(
        "전자제품",
        Product(
            name="Prototype-Electronics",
            category="전자제품",
            price=0,
            tax_rate="10%",
            shipping_policy="2일 이내 배송",
            return_policy="7일 이내 무료 반품"
        )
    )

    registry.register_prototype(
        "도서",
        Product(
            name="Prototype-Book",
            category="도서",
            price=0,
            tax_rate="5%",
            shipping_policy="3일 이내 배송",
            return_policy="반품 불가"
        )
    )

    return registry


# 클라이언트: 새 상품 생성 요청 시 워크플로우
def simulate_product_creation():
    registry = initialize_registry()

    # 새 상품 생성
    macbook = registry.create_product("전자제품", "MacBook Air M3", 1690000)
    book = registry.create_product("도서", "Clean Architecture", 35000)

    # 출력
    print("📦 신규 등록 상품:")
    print(macbook)
    print(book)


# 실행
simulate_product_creation()

사례 3: MMORPG 게임의 캐릭터 생성 시스템

대규모 멀티플레이어 온라인 롤플레잉 게임에서 플레이어 캐릭터와 NPC(Non-Player Character) 를 효율적으로 생성하고 관리하는 시스템을 구현해야 하는 상황.

시스템 구성

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
                    ┌─────────────────────┐
                    │   GameClient        │
                    │  (캐릭터 생성 요청)   │
                    └──────────┬──────────┘
                    ┌─────────────────────┐
                    │ CharacterFactory    │
                    │  (캐릭터 생성 관리자) │
                    └──────────┬──────────┘
            ┌─────────────────────────────────────────┐
            │        CharacterRegistry                │
            │     (캐릭터 프로토타입 레지스트리)          │
            ├─────────────────────────────────────────┤
            │ - warriorPrototype: WarriorCharacter    │
            │ - magePrototype: MageCharacter          │  
            │ - archerPrototype: ArcherCharacter      │
            │ - npcPrototype: NPCCharacter            │
            └──────────┬──────────────────────────────┘
            ┌─────────────────────┐
            │     Character       │
            │   (Abstract Base)   │
            ├─────────────────────┤
            │ + clone(): Character│
            │ + initialize()      │
            │ + render()          │
            └───────────┬─────────┘
          ┌─────────────┼───────────────┐
          │             │               │
┌─────────┴───────┐ ┌───┴─────────┐ ┌───┴───────────┐
│WarriorCharacter │ │MageCharacter│ │ArcherCharacter│
├─────────────────┤ ├─────────────┤ ├───────────────┤
│+ clone()        │ │+ clone()    │ │+ clone()      │
│+ swordAttack()  │ │+ castSpell()│ │+ bowAttack()  │
└─────────────────┘ └─────────────┘ └───────────────┘

워크플로:

  1. 시스템 초기화 단계:

    • 게임 서버 시작 시 각 캐릭터 클래스의 기본 프로토타입 생성
    • 프로토타입에 기본 스탯, 스킬, 장비 설정
    • CharacterRegistry 에 모든 프로토타입 등록
  2. 플레이어 캐릭터 생성:

    • 플레이어가 캐릭터 생성 화면에서 직업 (전사/마법사/궁수) 선택
    • CharacterFactory 가 선택된 직업에 해당하는 프로토타입 조회
    • 프로토타입을 복제하여 새로운 캐릭터 인스턴스 생성
    • 플레이어가 설정한 이름, 외형 정보를 복제된 캐릭터에 적용
  3. NPC 대량 생성:

    • 게임 월드의 각 지역에 필요한 NPC 타입과 수량 결정
    • 해당 NPC 프로토타입을 복제하여 다수의 인스턴스 생성
    • 각 NPC 에 고유한 위치, AI 패턴, 대화 내용 설정
  4. 런타임 동적 생성:

    • 특별 이벤트나 레이드에서 새로운 몬스터 등장
    • 기존 프로토타입을 복제하고 이벤트에 맞는 특수 능력 추가
    • 플레이어 레벨에 맞춰 스탯 조정

구체적 구현 예시

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 캐릭터 프로토타입 인터페이스
public abstract class Character implements Cloneable {
    protected String name;
    protected int level;
    protected int hp, mp;
    protected Map<String, Integer> stats;
    protected List<Skill> skills;
    protected Equipment equipment;
    
    public abstract Character clone();
    public abstract void performSpecialAttack();
}

// 전사 캐릭터 구체 구현
public class WarriorCharacter extends Character {
    @Override
    public WarriorCharacter clone() {
        WarriorCharacter cloned = new WarriorCharacter();
        cloned.level = this.level;
        cloned.hp = this.hp;
        cloned.mp = this.mp;
        cloned.stats = new HashMap<>(this.stats);
        cloned.skills = new ArrayList<>(this.skills);
        cloned.equipment = this.equipment.deepCopy();
        return cloned;
    }
    
    @Override
    public void performSpecialAttack() {
        // 전사 고유의 특수 공격
    }
}

// 캐릭터 레지스트리
public class CharacterRegistry {
    private static final Map<String, Character> prototypes = new HashMap<>();
    
    static {
        // 기본 프로토타입들 초기화
        WarriorCharacter warrior = new WarriorCharacter();
        warrior.setLevel(1);
        warrior.setHp(100);
        warrior.getStats().put("strength", 15);
        warrior.getStats().put("dexterity", 10);
        prototypes.put("WARRIOR", warrior);
        
        MageCharacter mage = new MageCharacter();
        mage.setLevel(1);
        mage.setHp(60);
        mage.setMp(100);
        mage.getStats().put("intelligence", 15);
        mage.getStats().put("wisdom", 12);
        prototypes.put("MAGE", mage);
    }
    
    public static Character getCharacter(String type) {
        Character prototype = prototypes.get(type);
        return prototype != null ? prototype.clone() : null;
    }
}

// 캐릭터 팩토리
public class CharacterFactory {
    public Character createPlayerCharacter(String characterClass, String playerName) {
        Character character = CharacterRegistry.getCharacter(characterClass);
        character.setName(playerName);
        character.setLevel(1); // 새 플레이어는 1레벨부터 시작
        return character;
    }
    
    public List<Character> createNPCs(String npcType, int count) {
        List<Character> npcs = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            Character npc = CharacterRegistry.getCharacter(npcType);
            npc.setName("NPC_" + npcType + "_" + (i + 1));
            // NPC별 고유 설정 추가
            npcs.add(npc);
        }
        return npcs;
    }
}

Prototype Pattern 의 역할

  1. 성능 최적화: 복잡한 캐릭터 초기화 (스킬 트리 계산, 장비 설정, AI 패턴 로딩) 과정을 한 번만 수행하고 이후 복제로 빠른 생성
  2. 메모리 효율성: 기본 프로토타입들을 공유하여 메모리 사용량 최적화
  3. 유연한 확장: 새로운 캐릭터 클래스나 변형 추가 시 기존 코드 수정 없이 프로토타입만 추가
    1. 동적 구성: 게임 이벤트나 플레이어 행동에 따라 런타임에 다양한 캐릭터 생성

구현 예시

Python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import copy

class PrototypeRegistry:
    def __init__(self):
        self._protos = {}

    def register(self, name, obj):
        self._protos[name] = obj

    def unregister(self, name):
        del self._protos[name]

    def clone(self, name, **attrs):
        proto = self._protos.get(name)
        if not proto:
            raise ValueError(f"No prototype registered: {name}")
        obj = copy.deepcopy(proto)
        obj.__dict__.update(attrs)
        return obj

# Concrete Prototype
class Car:
    def __init__(self, make, model, details):
        self.make = make
        self.model = model
        self.details = details  # dict

# registry 설정
reg = PrototypeRegistry()
reg.register("mustang", Car("Ford", "Mustang", {"color": "Red", "horsepower": 400}))

# clone 응용
new_car = reg.clone("mustang", details={"color": "Blue", "horsepower": 420})
print(vars(new_car))

Javascript

다음은 전자상거래 플랫폼의 상품 프로토타입 시스템을 JavaScript 로 구현한 예시:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
// 프로토타입 인터페이스 정의
class ProductPrototype {
    constructor() {
        if (this.constructor === ProductPrototype) {
            throw new Error("Abstract class cannot be instantiated");
        }
    }
    
    // 추상 메서드 - 하위 클래스에서 구현 필요
    clone() {
        throw new Error("Clone method must be implemented");
    }
}

// 전자제품 프로토타입 구현
class ElectronicsPrototype extends ProductPrototype {
    constructor() {
        super();
        // 전자제품 공통 속성 초기화
        this.category = "Electronics";
        this.warranty = "1 year";
        this.shippingWeight = 2.0;
        this.taxRate = 0.08;
        this.returnPolicy = "30-day return";
        this.certifications = ["CE", "FCC"];
        this.powerRequirements = "AC 100-240V";
    }
    
    // 깊은 복사 구현
    clone() {
        const cloned = new ElectronicsPrototype();
        
        // 기본 속성 복사
        cloned.category = this.category;
        cloned.warranty = this.warranty;
        cloned.shippingWeight = this.shippingWeight;
        cloned.taxRate = this.taxRate;
        cloned.returnPolicy = this.returnPolicy;
        cloned.powerRequirements = this.powerRequirements;
        
        // 배열의 깊은 복사
        cloned.certifications = [this.certifications];
        
        return cloned;
    }
    
    // 개별 상품 정보 설정 메서드
    setProductDetails(name, price, brand, model) {
        this.productName = name;
        this.price = price;
        this.brand = brand;
        this.model = model;
        this.productId = `ELEC_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        return this;
    }
    
    // 제품 정보 출력
    getProductInfo() {
        return {
            productId: this.productId,
            productName: this.productName,
            category: this.category,
            price: this.price,
            brand: this.brand,
            model: this.model,
            warranty: this.warranty,
            taxRate: this.taxRate,
            certifications: this.certifications
        };
    }
}

// 의류 프로토타입 구현
class ClothingPrototype extends ProductPrototype {
    constructor() {
        super();
        // 의류 공통 속성 초기화
        this.category = "Clothing";
        this.warranty = "No warranty";
        this.shippingWeight = 0.5;
        this.taxRate = 0.06;
        this.returnPolicy = "14-day return";
        this.careInstructions = ["Machine wash cold", "Do not bleach"];
        this.materials = [];
    }
    
    clone() {
        const cloned = new ClothingPrototype();
        
        cloned.category = this.category;
        cloned.warranty = this.warranty;
        cloned.shippingWeight = this.shippingWeight;
        cloned.taxRate = this.taxRate;
        cloned.returnPolicy = this.returnPolicy;
        
        // 배열의 깊은 복사
        cloned.careInstructions = [this.careInstructions];
        cloned.materials = [this.materials];
        
        return cloned;
    }
    
    setProductDetails(name, price, brand, size, color) {
        this.productName = name;
        this.price = price;
        this.brand = brand;
        this.size = size;
        this.color = color;
        this.productId = `CLOTH_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        return this;
    }
    
    getProductInfo() {
        return {
            productId: this.productId,
            productName: this.productName,
            category: this.category,
            price: this.price,
            brand: this.brand,
            size: this.size,
            color: this.color,
            careInstructions: this.careInstructions,
            materials: this.materials
        };
    }
}

// 프로토타입 레지스트리 구현
class ProductPrototypeRegistry {
    constructor() {
        this.prototypes = new Map();
        this.initializeDefaultPrototypes();
    }
    
    // 기본 프로토타입들 초기화
    initializeDefaultPrototypes() {
        this.registerPrototype("electronics", new ElectronicsPrototype());
        this.registerPrototype("clothing", new ClothingPrototype());
    }
    
    // 프로토타입 등록
    registerPrototype(key, prototype) {
        if (!(prototype instanceof ProductPrototype)) {
            throw new Error("Prototype must extend ProductPrototype");
        }
        this.prototypes.set(key, prototype);
        console.log(`Prototype '${key}' registered successfully`);
    }
    
    // 프로토타입 조회 및 복제
    getPrototype(key) {
        const prototype = this.prototypes.get(key);
        if (!prototype) {
            throw new Error(`Prototype '${key}' not found`);
        }
        return prototype.clone();
    }
    
    // 등록된 프로토타입 목록 조회
    getAvailablePrototypes() {
        return Array.from(this.prototypes.keys());
    }
    
    // 프로토타입 제거
    removePrototype(key) {
        const removed = this.prototypes.delete(key);
        if (removed) {
            console.log(`Prototype '${key}' removed successfully`);
        }
        return removed;
    }
}

// 상품 팩토리 클라이언트
class ProductFactory {
    constructor() {
        this.registry = new ProductPrototypeRegistry();
    }
    
    // 상품 생성 메서드
    createProduct(category, productDetails) {
        try {
            // 성능 측정 시작
            const startTime = performance.now();
            
            // 프로토타입 복제
            const product = this.registry.getPrototype(category);
            
            // 개별 상품 정보 설정
            if (category === "electronics") {
                product.setProductDetails(
                    productDetails.name,
                    productDetails.price,
                    productDetails.brand,
                    productDetails.model
                );
            } else if (category === "clothing") {
                product.setProductDetails(
                    productDetails.name,
                    productDetails.price,
                    productDetails.brand,
                    productDetails.size,
                    productDetails.color
                );
            }
            
            // 성능 측정 종료
            const endTime = performance.now();
            console.log(`Product created in ${(endTime - startTime).toFixed(2)}ms`);
            
            return product;
        } catch (error) {
            console.error("Error creating product:", error.message);
            return null;
        }
    }
    
    // 대량 상품 생성 (성능 테스트용)
    createBulkProducts(category, count = 1000) {
        const startTime = performance.now();
        const products = [];
        
        for (let i = 0; i < count; i++) {
            const productDetails = {
                name: `Product ${i}`,
                price: 100 + i,
                brand: `Brand ${i % 10}`,
                model: `Model ${i}`,
                size: ["S", "M", "L", "XL"][i % 4],
                color: ["Red", "Blue", "Green", "Black"][i % 4]
            };
            
            const product = this.createProduct(category, productDetails);
            if (product) {
                products.push(product);
            }
        }
        
        const endTime = performance.now();
        console.log(`Created ${products.length} products in ${(endTime - startTime).toFixed(2)}ms`);
        console.log(`Average time per product: ${((endTime - startTime) / count).toFixed(4)}ms`);
        
        return products;
    }
}

// 사용 예시 및 데모
function demonstratePrototypePattern() {
    console.log("=== 프로토타입 패턴 데모 시작 ===\n");
    
    // 팩토리 인스턴스 생성
    const factory = new ProductFactory();
    
    // 사용 가능한 프로토타입 확인
    console.log("사용 가능한 프로토타입:", factory.registry.getAvailablePrototypes());
    console.log();
    
    // 개별 상품 생성 예시
    console.log("1. 개별 상품 생성:");
    
    // 전자제품 생성
    const laptop = factory.createProduct("electronics", {
        name: "Gaming Laptop Pro",
        price: 1299.99,
        brand: "TechCorp",
        model: "GL-2024"
    });
    
    if (laptop) {
        console.log("전자제품 생성 완료:", laptop.getProductInfo());
    }
    
    // 의류 생성
    const tshirt = factory.createProduct("clothing", {
        name: "Cotton T-Shirt",
        price: 29.99,
        brand: "FashionCo",
        size: "M",
        color: "Blue"
    });
    
    if (tshirt) {
        console.log("의류 생성 완료:", tshirt.getProductInfo());
    }
    
    console.log("\n2. 복제된 객체의 독립성 테스트:");
    
    // 동일한 프로토타입에서 여러 객체 생성
    const phone1 = factory.createProduct("electronics", {
        name: "Smartphone X",
        price: 799.99,
        brand: "MobileTech",
        model: "SMX-2024"
    });
    
    const phone2 = factory.createProduct("electronics", {
        name: "Smartphone Y",
        price: 899.99,
        brand: "MobileTech",
        model: "SMY-2024"
    });
    
    // 객체 독립성 확인
    phone1.certifications.push("Custom Cert");
    
    console.log("Phone1 certifications:", phone1.certifications);
    console.log("Phone2 certifications:", phone2.certifications);
    console.log("Certifications are independent:", 
                phone1.certifications.length !== phone2.certifications.length);
    
    console.log("\n3. 성능 테스트 - 대량 객체 생성:");
    
    // 전자제품 1000개 생성
    factory.createBulkProducts("electronics", 1000);
    
    // 의류 1000개 생성  
    factory.createBulkProducts("clothing", 1000);
    
    console.log("\n=== 프로토타입 패턴 데모 완료 ===");
}

// 데모 실행
demonstratePrototypePattern();

실무에서 효과적으로 적용하기 위한 고려사항 및 주의할 점

카테고리항목설명권장 사항
1. 설계 단계복제 전략 결정얕은 복사 vs 깊은 복사의 선택 필요객체 구조, 독립성, 성능 요구사항 고려 후 전략 수립
프로토타입 대상 식별어떤 객체를 프로토타입으로 만들지 판단생성 비용 높거나 반복 사용되는 객체 중심 선정
복제 인터페이스 설계일관된 복제 메서드 정의 (clone, copy)인터페이스 기반 설계 (Cloneable, Copyable)
스코프 정의프로토타입 객체의 생명주기와 범위 지정전역 (싱글톤) vs 지역 스코프 구분, 의존성 주입 프레임워크 활용
2. 구현 단계복제 메서드 구현모든 필드를 정확히 복제하는지 구현 확인super.clone() + 필드별 수동 복제, 중첩 객체 처리
복제 방식 명확화얕은 복사와 깊은 복사의 구현 차이 명확히 분리copy.copy() vs copy.deepcopy() 또는 커스텀 로직
순환 참조 방지복제 중 순환 참조로 인한 무한 루프 방지 필요visited 맵 활용하여 이미 복제된 객체 추적
예외 처리복제 실패에 대비한 예외 처리 및 복구 로직 필요CloneNotSupportedException, fallback 로직 구현
버전 호환성 관리프로토타입 구조 변경 시 하위 호환성 보장스키마 버전 관리, 마이그레이션 전략 포함
3. 성능 최적화복제 비용 분석복제 비용 vs 새 객체 생성 비용 비교JMH/VisualVM 등으로 성능 비교 후 기준 수립
메모리 사용량 모니터링복제 및 레지스트리의 메모리 효율성 관리 필요GC 튜닝, 메모리 임계치 설정, 사용량 시각화
캐시 및 객체 풀링 활용자주 복제되는 객체를 캐싱하거나 풀에서 관리Registry Pattern, LRU 캐시, 풀 초기화 전략
Copy-on-Write지연 복제 전략으로 실제 수정 시점까지 복사 유예읽기 전용 객체 공유, 쓰기 시 clone()
병렬 복제대량 복제 작업의 병렬 처리로 성능 향상ThreadPool, asyncio, GPU 클론 (CUDA) 등 활용
4. 테스트 단계복제 정확성 검증복제 객체와 원본 객체의 상태 일치 확인단위 테스트: equals 검증, 통합 테스트: 대량 복제 시나리오
독립성 테스트복제 후 한 객체 수정이 다른 객체에 영향을 미치는지 확인깊은 복사 여부 확인, 참조 분리 검증
커버리지 확보다양한 구조의 clone 동작 확인Circular 참조, nested 객체, null 필드 등 포함
성능 테스트복제 성능 vs 생성 성능 비교대량 클론 시 메모리 사용량 및 처리 시간 측정
5. 보안 고려사항민감 정보 처리복제 중 개인정보, 토큰 등 민감한 정보 유출 방지복제 대상에서 제외, 복제 전 암호화 필드 처리
접근 권한 관리레지스트리 및 clone 호출 권한 제어역할 기반 접근 제어 (RBAC), read/write 권한 분리
6. 운영 관리레지스트리 관리자주 사용하는 프로토타입을 등록/삭제하며 생명주기 관리불필요한 객체 정리, 자동 정리 스케줄, TTL 설정
모니터링 및 경고 시스템복제 횟수, 실패율, 메모리 사용량 등 운영 지표 수집Prometheus, Grafana, APM 연동
자동화 도구 통합CI/CD 와 테스트, 배포, 성능 모니터링 자동화프로토타입 벤치마크 자동화, 레지스트리 상태 점검 자동화

테스트 전략

리팩토링 전략

활용 시 흔한 실수

성능을 최적화하기 위한 고려사항

카테고리전략/항목설명권장 방안
1. 메모리 최적화지연 복제 (Lazy Cloning)실제 수정 시점까지 복제를 미루는 전략Copy-on-Write 구현, Proxy 패턴, 읽기 전용 접근 시 원본 공유
불변 객체 공유변경되지 않는 객체는 복제 없이 참조 공유String, Enum, 기본 타입 래퍼 클래스 재사용
객체 풀링 (Object Pooling)자주 사용되는 복제 객체를 풀에 등록하여 재사용풀 워밍업, LRU 캐시 알고리즘, GC 연동
불필요한 필드 제거복제 시 불필요한 필드까지 포함하면 메모리 낭비transient 지정, 복제 대상 필드 최소화
2. 실행 성능 최적화병렬 복제 (Parallel Cloning)독립적인 복제 작업을 병렬 처리하여 속도 향상ThreadPool, concurrent.futures, GPU 병렬 처리 (CUDA 등)
캐싱 전략동일 복제 요청에 대해 결과 재사용Prototype 캐시 + 만료 정책 (LRU, TTL), 캐시 히트율 모니터링
사전 계산 값 활용복제 시 반복 계산이 필요한 값은 미리 계산 후 포함hashCode, 직렬화된 byte 배열 등 사전 계산 필드 추가
3. 직렬화 기반 복제효율적 직렬화깊은 복사 시 직렬화 성능 향상Binary 직렬화 사용, Kryo / Avro / Protobuf 등 적용
압축 직렬화직렬화 데이터의 크기 감소로 성능 향상GZIP, LZ4 압축 알고리즘 적용
4. 확장성 최적화계층적 복제복제를 여러 단계로 분리하여 확장성 확보기본 복제 후 후속 속성 초기화 분리, 다형적 복제 로직 구현
스트리밍 복제대용량 객체를 스트림 방식으로 점진적으로 복제Generator / AsyncIterator 기반 구현, 메모리 제한 처리
분산 복제마이크로서비스 간 공유를 위한 복제 전략프로토타입 레지스트리 서버, 서비스 메시지 큐 연동, 상태 동기화 구현
동적 로딩필요한 시점에만 프로토타입 로딩DI 컨테이너 통합, 모듈 시스템 활용, Lazy Initialization
5. 운영 최적화성능 모니터링복제 성능, 실패율, 메모리 사용량 등 지표 수집Prometheus, Grafana 연동, 복제 시간/GC 로그 추적
자동 튜닝사용 패턴에 따라 복제 전략 자동 최적화ML 기반 튜닝, 접근 패턴 분석 기반 전략 스위칭
경고 시스템성능 저하/오류 감지 시 알림 제공APM 연동, 경고 임계값 설정, Slack/Webhook 알림 연결
6. 테스트 및 안정성복제 범위 제한필요한 속성만 복제하여 경량화clone() 내 필드 필터링, 맞춤형 복제 전략 사용
상태 일관성 검증복제 후 객체의 상태가 원본과 일관성을 유지하도록 관리테스트 케이스 작성, 복제 전후 유효성 검증 로직 추가
clone 비용 측정clone() 의 시간/메모리 비용 분석Python: timeit, Java: JMH, VisualVM, JProfiler 등 사용
테스트 데이터 복제다양한 테스트 케이스 생성을 위한 프로토타입 활용테스트 전용 Template Object 생성, Mock/Stub 등록 시스템 적용
7. 전략적 조합메모이제이션동일한 입력에 대해 clone 결과 캐싱functools.lru_cache, Key-Value 기반 hash 캐싱
Prototype + Registry자주 사용하는 프로토타입의 등록 및 재사용Registry Pattern 구현, 전역 접근 포인트 제공
Lazy + Pooling초기에는 지연 생성, 이후에는 풀을 통해 재사용첫 요청 시 복제 후 풀에 등록, 이후 풀에서 직접 제공

주제와 관련하여 주목할 내용

카테고리세부 주제항목설명
1. 설계 원칙프로토타입 패턴 구조객체 복제객체를 복제하여 생성 비용 절감
결합도 감소코드가 구체 클래스에 의존하지 않고 인터페이스만 참조
2. 실무 적용유연한 객체 생성동적 객체 생성런타임에 다양한 타입의 객체 생성 가능
설정 관리다양한 설정 조합을 효율적으로 구성 및 복제
3. 복제 기법복사 방식 구분얕은 복사 / 깊은 복사얕은 복사는 참조 공유, 깊은 복사는 재귀적 전체 복사
지연 복사 전략Copy-on-Write수정 시점까지 복제를 지연해 메모리 최적화
구조적 공유변경되지 않은 부분만 공유불변 객체 시스템에서 메모리 효율화
4. 관리 전략레지스트리 패턴PrototypeRegistry다양한 프로토타입 객체를 이름 기반으로 등록 및 재사용
5. 패턴 결합생성 패턴 비교Factory / Builder 비교Factory 는 생성, Prototype 은 복제, Builder 는 단계적 생성
Builder + Prototype복사 후 커스터마이징 가능clone().withX() 형태로 속성 변경 가능
Prototype + Registry동적 프로토타입 관리필요한 시점에만 객체 등록 후 복제
6. 클라우드 기술클라우드 네이티브컨테이너화된 프로토타입Docker 로 프로토타입을 이미지화하여 재사용
서버리스 환경FaaS 기반 프로토타입AWS Lambda, Azure Functions 등에서 템플릿 객체 활용
7. 프레임워크 통합UI 프레임워크React/Vue 컴포넌트 복제UI 컴포넌트를 상태 기반 복제로 재사용
Spring FrameworkPrototype Scope 활용Bean 생성 전략과 디자인 패턴의 결합
8. 성능 기술고성능 복제WebAssembly 기반 복제네이티브 수준의 성능으로 객체 복제 처리
병렬 복제GPU 기반 병렬 처리CUDA/OpenCL 등을 통한 대량 복제
프로파일링/벤치마크JMH, VisualVM 등 도구복제 성능 측정 및 메모리 사용 분석
9. 보안 고려불변 프로토타입블록체인 기반 무결성 보장위변조 방지를 위한 해시 기반 객체 복제 관리
안전한 복제암호화된 복제 메커니즘민감 데이터에 대한 보안 복제 구현
10. 테스트 전략테스트 자동화테스트 데이터 템플릿 복제다양한 테스트 시나리오 구성에 사용
테스트 더블Mock/Stub 복제 객체 생성테스트용 의존성 객체 자동 생성
11. 분산 시스템상태 복제분산 시스템 내 상태 일관성여러 노드에 복제 객체 분산 관리
이벤트 소싱과 복제상태 스냅샷 기반 복제이벤트 기반 저장소에서 복제 객체 구성
12. 함수형 프로그래밍불변 객체 복제immutable 구조의 복제 전략데이터 변경 없이 복사본을 통해 상태 변경
13. 언어별 구현Java 복제 구현clone vs copy-constructorcloneable 인터페이스 사용 시 주의점 및 대안 전략
Python 복제 구현copy.copy vs deepcopy표준 copy 모듈의 얕은/깊은 복사 차이 분석
14. 기타 고급 기법참조 계수 기반 복제스마트 포인터 복제C++ 등에서 안전한 메모리 관리와 복제
버전 관리복제 객체의 마이그레이션구조 변경 시에도 일관성 유지

추가 학습 주제

대분류중분류세부 주제설명
1. 고급 구현메타프로그래밍리플렉션 기반 동적 복제런타임에 구조 분석을 통해 객체를 복제
제네릭 프로토타입타입 안전성 확보자바/타입스크립트 등에서 제네릭 기반 복제 구현
함수형 복제불변 객체 기반 복제 전략클론 없이 새 객체로 상태 이전 (ex. Redux 스타일)
2. 성능 최적화객체 풀링 + 프로토타입메모리 재사용 전략Object Pool 과 결합하여 생성 비용 절감
비동기 복제Future/Promise 기반 복제CompletableFuture 등으로 비동기적 복제 수행
스트리밍 복제점진적/부분 복제대용량 객체 복제를 스트림 기반으로 처리
3. 패턴 결합Builder + Prototype커스터마이징 복제복제 후 Builder 로 추가 속성 지정
Factory + Prototype생성 + 복제 혼합 전략Factory 에서 프로토타입을 생성하거나 복제하여 반환
Command + Prototype명령 객체 복제Undo/Redo 등에서 명령 객체를 복제하여 사용
4. 분산/운영 환경분산 프로토타입프로토타입의 네트워크 공유클러스터 또는 분산 환경에서 복제 객체 공유
버전 관리프로토타입 버전 및 마이그레이션 관리데이터/클래스 변경에 따른 복제 구조의 안정적 전환
보안 복제안전한 클론민감 데이터 마스킹, 복제 제어 등 보안 관점 고려
5. 클라우드 및 아키텍처마이크로서비스 복제서비스 템플릿 기반 객체 복제서비스별 기본 구조 복제, 배포 템플릿 활용
이벤트 기반 복제이벤트 소싱 연계Snapshot/State 복제를 이벤트와 연계
서버리스 환경 복제함수 단위 프로토타입 관리FaaS 모델에서 함수 객체를 복제 및 관리
6. 데이터/엔티티 활용ETL 파이프라인 복제템플릿 파이프라인 구성반복되는 ETL 작업을 복제하여 자동화
스키마 진화스키마 복제 및 이력 관리데이터 구조 변경 시 이전 버전 복제 유지
ECS 기반 엔티티 복제게임 엔티티 구성요소 복제컴포넌트 단위로 상태를 복제하여 새로운 엔티티 구성
절차적 생성과 복제콘텐츠의 조합 + 복제규칙 기반 생성 구조에 프로토타입 적용
7. UI/UX 및 테스트디자인 시스템 복제UI 컴포넌트 복제Button, Modal 등 템플릿 UI 객체 복제
반응형 레이아웃 템플릿디바이스별 템플릿 복제다양한 해상도 대응 레이아웃 객체 복제
테스트 데이터 템플릿테스트 객체 템플릿화특정 시나리오에 맞는 데이터 복제 구조 활용
성능 테스트용 복제대량 객체 부하 테스트수만 개 객체 복제 → 부하 테스트 등 실험
8. 구현 및 테스트 전략Registry 관리객체 레지스트리 운영복제 대상 등록 및 동적 접근
얕은/깊은 복사복사 방식 비교copy.copy vs copy.deepcopy 등 구현 방식 선택
순환 참조 복제내부 참조 구조 처리A→B→A 형태의 구조에서 클론 안정성 확보
단위 및 속성 기반 테스트복제 후 무결성 테스트독립성/불변성/성능 테스트 전략
9. 실무 최적화 기술자동 복제 라이브러리Dozer, ModelMapper 등Java 등에서 필드 기반 자동 복제
구조적 공유메모리 절약 클론 전략변경되지 않은 영역은 참조 공유
Copy-on-Write쓰기 시점 복제성능 최적화를 위한 복사 전략
직렬화 기반 복제JSON/XML 직렬화 후 복제시스템 간 객체 교환과 함께 복제 수행
10. 필수 개념 및 기반 지식가비지 컬렉션복제 객체의 메모리 해제 이해불필요 객체 메모리 누수 방지
상속과 합성 비교객체 생성 전략으로의 차이점프로토타입 vs 상속 기반 생성 구조 구분
스레드 안전성멀티스레드 환경 복제 제어동기화, 불변 객체 활용 전략
CAP 이론과 일관성분산 환경에서 복제 객체의 정합성Registry 공유 시 Consistency vs Availability
프로파일링과 병목 분석clone 성능 측정복제 성능 확인 및 최적화 지점 분석
프로토타입 인터페이스 분리DIP 적용을 위한 클론 인터페이스 분리클라이언트와 복제 객체 간 결합도 최소화

용어 정리

카테고리용어설명
핵심 패턴 구성Prototype복제를 위한 인터페이스를 제공하는 기본 객체
ConcretePrototypePrototype 인터페이스를 구현하며 실제 복제 로직을 포함하는 클래스
Client프로토타입을 통해 객체를 복제하는 클라이언트 코드
복제 기법Clone기존 객체를 기반으로 동일한 상태의 객체를 복제하는 행위
Clone Method복제를 수행하는 메서드 (예: clone())
Shallow Copy참조는 공유하고 기본 필드만 복제하는 얕은 복사
Deep Copy참조 객체까지 모두 재귀적으로 복제하는 깊은 복사
Copy Constructor기존 객체를 기반으로 복제하는 생성자 방식
Serialization Clone직렬화 후 역직렬화로 깊은 복사를 수행하는 기법
Copy-on-Write실제 변경 시점까지 복제를 지연하여 성능을 최적화하는 전략
객체 관리Prototype Registry키 - 값 형태로 프로토타입 객체들을 등록·관리하는 저장소
Prototype Manager프로토타입 객체의 생명주기를 총괄적으로 관리하는 시스템
Object Pool미리 생성된 객체를 재사용하는 풀 구조
구현 요소 (언어)copy.copy() (Python)파이썬의 얕은 복사를 수행하는 표준 라이브러리 함수
copy.deepcopy() (Python)파이썬의 깊은 복사를 수행하는 표준 라이브러리 함수
Cloneable (Java)Java 에서 clone() 사용을 위해 구현해야 하는 인터페이스
최적화 전략Lazy Clone필요 시점까지 복제를 지연하여 불필요한 리소스 낭비 방지
Lazy Initialization객체 생성 자체를 지연하는 일반적 초기화 전략
Memoization계산 결과를 캐싱하여 동일 계산 반복을 방지
Structural Sharing변경되지 않은 객체 구조를 공유하여 메모리를 절약하는 방식
이론적 개념Circular Reference복제 시 순환 참조가 발생하는 구조 (ex. A → B → A)
Immutable Object생성 후 내부 상태 변경이 불가능한 객체
추상화 및 확장Template Method알고리즘의 뼈대를 정의하고 세부 구현은 하위 클래스에서 정의하는 패턴
Covariant Return Type오버라이딩된 메서드에서 반환 타입을 더 구체적으로 지정할 수 있는 기능
비유적 개념Mitotic Division생물학적 유사 분열에 빗댄 객체 복제의 은유

참고 및 출처