프로토타입 패턴

프로토타입 패턴(Prototype Pattern)은 객체 생성 디자인 패턴 중 하나로, 새로운 객체를 생성할 때 클래스의 인스턴스를 직접 생성하는 대신 기존에 존재하는 객체를 복제(clone)하여 새로운 객체를 만든다. 이 패턴은 객체 생성 비용이 높거나, 동적으로 객체 구조가 변할 때, 혹은 복제 과정에서 객체의 상태를 그대로 유지하고 싶을 때 유용하게 활용된다.

1. 의도

  • 복제 기반의 객체 생성: 기존 객체를 복제함으로써 복잡한 초기화 과정을 피하고, 동일한 객체 구조를 빠르게 재사용한다.
  • 동적 객체 구성을 지원: 런타임 시에 객체의 구성을 변경하거나 새로운 종류의 객체를 추가할 때, 클래스를 추가 정의할 필요 없이 기존 프로토타입을 복제한다.

2. 적용 가능성

다음과 같은 상황에서 프로토타입 패턴을 적용한다.

  • 객체 생성 비용이 높은 경우(예: 데이터베이스 연결, 복잡한 연산, 대용량 메모리 할당 등).
  • 제품군이 다양하고, 각각의 제품을 서브클래스로 구현하기보다 동일한 인터페이스를 가진 프로토타입을 복제하여 사용하고자 할 때.
  • 시스템이 실행 중에 새로운 객체 유형을 동적으로 추가해야 하는 경우.

3. 구성 요소

역할 설명
Prototype 복제 가능한 인터페이스를 정의한다. 보통 clone() 메서드를 선언한다.
ConcretePrototype Prototype을 구현하고 실제 복제 로직을 제공한다. 깊은 복사와 얕은 복사 중 하나를 구현한다.
Client Prototype 인터페이스를 통해 객체를 복제하고, 필요에 따라 복제된 객체를 이용한다.

4. 협력 방식

  1. 클라이언트는 Prototype 인터페이스를 통해 복제하고자 하는 객체를 지정한다.
  2. ConcretePrototype은 자신을 복제하는 clone() 메서드를 구현한다.
  3. 클라이언트는 복제된 객체를 반환받아 기존 객체와는 독립적인 상태를 유지하며 사용한다.

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)과 결합되어 활용되고 있다.

참고 문헌

  1. Gamma, E., Helm, R., Johnson, R., Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison‑Wesley.
  2. Bloch, J. (2008). Effective Java (2nd ed.). Addison‑Wesley. – 복제와 clone() 구현에 대한 권고 사항.
  3. Meyer, B. (2014). Object‑Oriented Software Construction (2nd ed.). Prentice Hall. – 객체 복제와 깊은 복사에 대한 심층 논의.
둘러보기

더 찾아볼 만한 주제