프로토타입 패턴(Prototype Pattern)은 객체 생성 디자인 패턴 중 하나로, 새로운 객체를 생성할 때 클래스의 인스턴스를 직접 생성하는 대신 기존에 존재하는 객체를 복제(clone)하여 새로운 객체를 만든다. 이 패턴은 객체 생성 비용이 높거나, 동적으로 객체 구조가 변할 때, 혹은 복제 과정에서 객체의 상태를 그대로 유지하고 싶을 때 유용하게 활용된다.
1. 의도
- 복제 기반의 객체 생성: 기존 객체를 복제함으로써 복잡한 초기화 과정을 피하고, 동일한 객체 구조를 빠르게 재사용한다.
- 동적 객체 구성을 지원: 런타임 시에 객체의 구성을 변경하거나 새로운 종류의 객체를 추가할 때, 클래스를 추가 정의할 필요 없이 기존 프로토타입을 복제한다.
2. 적용 가능성
다음과 같은 상황에서 프로토타입 패턴을 적용한다.
- 객체 생성 비용이 높은 경우(예: 데이터베이스 연결, 복잡한 연산, 대용량 메모리 할당 등).
- 제품군이 다양하고, 각각의 제품을 서브클래스로 구현하기보다 동일한 인터페이스를 가진 프로토타입을 복제하여 사용하고자 할 때.
- 시스템이 실행 중에 새로운 객체 유형을 동적으로 추가해야 하는 경우.
3. 구성 요소
| 역할 | 설명 |
|---|---|
| Prototype | 복제 가능한 인터페이스를 정의한다. 보통 clone() 메서드를 선언한다. |
| ConcretePrototype | Prototype을 구현하고 실제 복제 로직을 제공한다. 깊은 복사와 얕은 복사 중 하나를 구현한다. |
| Client | Prototype 인터페이스를 통해 객체를 복제하고, 필요에 따라 복제된 객체를 이용한다. |
4. 협력 방식
- 클라이언트는
Prototype인터페이스를 통해 복제하고자 하는 객체를 지정한다. ConcretePrototype은 자신을 복제하는clone()메서드를 구현한다.- 클라이언트는 복제된 객체를 반환받아 기존 객체와는 독립적인 상태를 유지하며 사용한다.
5. 결과 및 장단점
| 장점 | 단점 |
|---|---|
| 성능 향상: 복제 비용이 새 객체를 직접 생성하는 비용보다 낮을 경우 성능이 개선된다. | 복제 복잡성: 깊은 복사와 얕은 복사를 구분해야 하며, 객체 그래프가 복잡할 경우 구현이 까다롭다. |
| 동적 확장성: 새로운 객체 유형을 런타임에 추가·수정하기 쉬우며, 서브클래스를 만들 필요가 없다. | 클래스 설계 제약: clone() 메서드를 호출할 수 있도록 객체가 복제 가능하도록 설계돼야 하며, Cloneable 인터페이스(자바) 등 언어별 제한이 있다. |
| 캡슐화 유지: 객체 내부 상태를 그대로 복제하므로 캡슐화를 깨지 않는다. | 복제 오류 위험: 복제 과정에서 불변 객체와 가변 객체를 적절히 처리하지 않으면 의도치 않은 공유 상태가 발생할 수 있다. |
6. 구현 예시 (Java)
// 1. Prototype 인터페이스
public interface Prototype<T> extends Cloneable {
T clone();
}
// 2. ConcretePrototype 구현
public class Document implements Prototype<Document> {
private String title;
private List<String> paragraphs = new ArrayList<>();
public Document(String title) {
this.title = title;
}
public void addParagraph(String text) {
paragraphs.add(text);
}
// 깊은 복사 구현
@Override
public Document clone() {
try {
Document copy = (Document) super.clone();
copy.paragraphs = new ArrayList<>(this.paragraphs); // 리스트 복제
return copy;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
@Override
public String toString() {
return "Document{" + "title='" + title + '\'' + ", paragraphs=" + paragraphs + '}';
}
}
// 3. Client 사용
public class PrototypeDemo {
public static void main(String[] args) {
Document original = new Document("샘플 보고서");
original.addParagraph("첫 번째 단락");
original.addParagraph("두 번째 단락");
Document copy = original.clone();
copy.addParagraph("추가된 단락");
System.out.println(original);
System.out.println(copy);
}
}
위 예시에서 Document 객체는 자체적으로 복제 로직을 제공한다. clone() 메서드는 객체의 내부 리스트를 새로운 리스트로 복사하여 깊은 복사를 수행한다. 이렇게 하면 복제된 객체는 원본과 독립적인 상태를 유지한다.
7. 관련 패턴
- 추상 팩토리(Abstract Factory): 프로토타입을 이용해 객체를 생성하는 팩터리 구현에 사용될 수 있다.
- 빌더(Builder): 복잡한 객체 구성을 단계적으로 수행한다면, 프로토타입 복제와 결합해 초기 템플릿을 재사용할 수 있다.
- 싱글턴(Singleton): 싱글턴 객체를 복제해야 할 경우 프로토타입 패턴은 사용되지 않으며, 오히려 싱글턴의 유일성을 보장한다.
8. 역사와 참고 문헌
프로토타입 패턴은 1994년 "Design Patterns: Elements of Reusable Object-Oriented Software"(Gang of Four, GoF)에서 Creational 카테고리의 하나로 정식 정의되었다. 이후 다양한 프로그래밍 언어와 프레임워크에서 표준 객체 복제 메커니즘(Cloneable, copy constructors, Object.clone)과 결합되어 활용되고 있다.
참고 문헌
- Gamma, E., Helm, R., Johnson, R., Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison‑Wesley.
- Bloch, J. (2008). Effective Java (2nd ed.). Addison‑Wesley. – 복제와
clone()구현에 대한 권고 사항. - Meyer, B. (2014). Object‑Oriented Software Construction (2nd ed.). Prentice Hall. – 객체 복제와 깊은 복사에 대한 심층 논의.