본문 바로가기
LV3_Advanced/GOF 패턴

Prototype (프로토타입) - 생성 패턴 #3

by 하타라시 2026. 2. 27.

목차

💡
  • 왜 퍼사드 패턴을 사용해야 하는가
  • 설계도는 어떻게 생겼나?
  • 실제로 어떻게 구현하나?
  • 장점과 단점은 무엇인가?

왜 프로토타입 패턴을 사용해야 하는가?

새로운 객체를 생성하는 비용(시간, 메모리 자원)이 클 때, 기존에 만들어둔 객체를 복제하여 새로운 객체를 생성하기 위해 사용합니다.

예를 들어, 설정값이 매우 많은 객체이거나 기본 템플릿을 기반으로 일부 값만 변경해 사용하는 객체인 경우 필요합니다.

⇒ 즉 new 키워드로 객체를 생성하는 대신에 기존 객체를 복제하여 생성 비용을 줄이는 방식입니다.

⇒ 객체를 생성하고 파괴하는데에도 자원이 사용되기 때문에 중요한 개념입니다.

설계도는 어떻게 생겼나?

clone() 메서드는 Object 클래스에 정의되어 있지만, Cloneable 인터페이스를 구현하지 않으면 clone 호출 시 예외가 발생합니다.

따라서 Monster는 객체 복제를 허용하기 위해 Cloneable 인터페이스를 구현합니다. 그리고 Monster를 상속받은 Orc는 상위 클래스의 clone 기능을 그대로 물려받아 자기 자신을 복제할 수 있게 됩니다.

⇒ Cloneable은 메서드를 가지지 않는 마커 인터페이스입니다.

⇒ 마커 인터페이스는 메서드를 정의하지 않으며, 객체에 특정 의미나 동작 가능 여부를 표시하기 위한 인터페이스입니다.

실패

실제로 어떻게 구현하나?

프로토타입 인터페이스

public abstract class Monster implements Cloneable {
    private String name;
    private int hp;

    public Monster(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }

    // 🌟 핵심: 자신을 복제하는 메서드
    @Override
    public Monster clone() {
        try {
            return (Monster) super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}

구체적인 클래스

public class Orc extends Monster {
    public Orc(String name, int hp) {
        super(name, hp);
    }
}

실행

public class Main {
    public static void main(String[] args) {
        Orc originalOrc = new Orc("오크 족장", 100);

        // 기존 객체를 복제하여 새로운 객체 생성
        Orc clonedOrc = (Orc) originalOrc.clone();
    }
}

clone()은 기본적으로 얕은 복사이기 때문에 참조형 필드가 있는 경우 예상치 못한 공유 문제가 발생할 수 있습니다.

장점과 단점은 무엇인가?

장점

  • 객체 생성 비용 감소
    • 복잡한 초기화 과정을 생략할 수 있습니다.
  • 런타임 중에 복제 가능
    • 프로그램 실행 중 동적으로 객체를 복사할 수 있습니다.

단점

  • 순환 참조 구조에서 난이도 증가
    • 그래프 구조처럼 객체 간 연결이 복잡한 경우 깊은 복사를 구현하는 과정이 매우 까다로워질 수 있습니다.
  • 복제의 복잡성
    • 내부에 리스트,객체와 같이 참조형 변수가 있다면, 얕은 복사와 깊은 복사를 명확히 구분하여 구현해야합니다.