생성 - 4. Prototype

mskimdev·2026년 5월 19일

Design Pattern

목록 보기
5/13

Prototype 패턴

객체를 하나 만드는 데 시간이 오래 걸린다고 가정해보자. DB에서 데이터를 읽어오거나, 복잡한 초기화 과정을 거쳐야 하는 경우다. 같은 구조의 객체가 여러 개 필요하다면 매번 처음부터 만드는 건 낭비다.

이미 만들어진 객체를 찍어내듯 복사하면 되지 않을까. 그게 Prototype 패턴이다.


Prototype 패턴이란

기존 객체를 복제(clone)해서 새 객체를 만드는 패턴이다. 객체 생성 비용이 클 때, 또는 거의 동일한 객체를 여러 개 만들어야 할 때 유용하다.

Java에서는 Cloneable 인터페이스와 clone() 메서드로 구현한다.


기본 구현

public class GameCharacter implements Cloneable {
    private String name;
    private int hp;
    private int attack;

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

    // 복제 메서드
    @Override
    public GameCharacter clone() {
        try {
            return (GameCharacter) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    public void setName(String name) { this.name = name; }

    @Override
    public String toString() {
        return name + " | HP: " + hp + " | ATK: " + attack;
    }
}
// 원본 생성
GameCharacter template = new GameCharacter("전사", 100, 30);

// 복제해서 새 캐릭터 생성
GameCharacter warrior1 = template.clone();
warrior1.setName("전사-1");

GameCharacter warrior2 = template.clone();
warrior2.setName("전사-2");

System.out.println(warrior1); // 전사-1 | HP: 100 | ATK: 30
System.out.println(warrior2); // 전사-2 | HP: 100 | ATK: 30

clone()Object에 정의된 메서드다. Cloneable을 구현하지 않으면 CloneNotSupportedException이 발생한다.


얕은 복사 vs 깊은 복사

super.clone()얕은 복사(Shallow Copy) 를 수행한다. 기본 타입 필드는 값이 복사되지만, 참조 타입 필드는 같은 객체를 가리키게 된다.

public class GameCharacter implements Cloneable {
    private String name;
    private int[] skills; // 참조 타입

    @Override
    public GameCharacter clone() {
        try {
            GameCharacter copy = (GameCharacter) super.clone();
            // 참조 타입은 따로 복사해야 함 — 깊은 복사
            copy.skills = this.skills.clone();
            return copy;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}

얕은 복사 상태에서 복제본의 skills를 수정하면 원본의 skills도 바뀐다. 서로 독립적인 객체가 되어야 한다면 참조 타입 필드는 직접 복사해야 한다.


Prototype Registry

미리 만들어둔 원본 객체들을 저장소에 등록해두고, 필요할 때 꺼내 복제하는 방식으로 확장할 수 있다.

public class CharacterRegistry {
    private Map<String, GameCharacter> registry = new HashMap<>();

    public void register(String key, GameCharacter character) {
        registry.put(key, character);
    }

    public GameCharacter get(String key) {
        return registry.get(key).clone();
    }
}
CharacterRegistry registry = new CharacterRegistry();
registry.register("warrior", new GameCharacter("전사", 100, 30));
registry.register("mage", new GameCharacter("마법사", 70, 60));

GameCharacter w1 = registry.get("warrior");
GameCharacter w2 = registry.get("warrior");

매번 DB를 조회하거나 복잡한 초기화를 반복하는 대신, 미리 만들어둔 객체를 복사해 쓰는 구조다.


언제 쓰는가

  • 객체 생성 비용이 커서 반복 생성이 부담될 때
  • 거의 동일한 객체를 여러 개 만들어야 할 때
  • 객체의 초기 상태를 템플릿처럼 재활용하고 싶을 때

Prototype은 new로 처음부터 만들지 않고, 기존 것을 베껴서 시작하는 패턴이다. 복사 후 달라질 부분만 수정하면 되니, 공통 구조가 많을수록 효율적이다.

profile
<- 개발 공부하는 나

0개의 댓글