프로토타입 패턴(Prototype Pattern)은 원본 객체를 복제(Clone)하여 새로운 객체를 생성하는 패턴입니다. 객체를 new 키워드로 생성하고 데이터베이스 조회 등을 통해 복잡하게 초기화하는 과정이 매우 비쌀(Cost가 높을) 때, 이미 완벽하게 세팅된 '프로토타입 객체'를 하나 만들어두고 이를 메모리 상에서 통째로 복사해서 사용하면 성능을 극적으로 높일 수 있습니다.
1. 프로토타입 패턴 구조 (Prototype UML)
클라이언트는 구체적인 클래스의 이름을 몰라도 clone() 메서드만 호출하면 원본과 완전히 동일한 상태의 새로운 인스턴스를 얻을 수 있습니다.
2. 깊은 복사(Deep Copy) vs 얕은 복사(Shallow Copy)
⚠️ 주의: 프로토타입 복제 시 참조 타입 처리
언어 차원에서 제공하는 기본적인 복제 기능(예: 자바의 clone(), 자바스크립트의 Object.assign())은 얕은 복사(Shallow Copy)를 수행합니다. 즉, 객체 내부에 배열이나 다른 객체의 참조(Reference)가 있다면 메모리 주소만 복사되어 원본과 클론이 내부 객체를 공유하게 됩니다. 이를 방지하려면 내부 참조 객체들까지 재귀적으로 복제하는 깊은 복사(Deep Copy)를 명시적으로 구현해야 합니다.
// 📂 Monster.js (JavaScript)
// 자바스크립트는 언어 자체가 '프로토타입 기반 언어'이므로,
// Object.assign 이나 전개 연산자(...)를 사용해 아주 쉽게 클론을 생성할 수 있습니다.
class Monster {
constructor(type, health, skills) {
this.type = type;
this.health = health;
this.skills = skills; // 배열 (참조 타입)
// ⚠️ 여기서 엄청나게 무거운 DB 조회 작업이 일어난다고 가정합니다.
console.log(`[시스템] ${this.type} 원본 객체 생성 및 리소스 로딩 (매우 무거운 작업)`);
}
// 얕은 복사(Shallow Copy) 메서드
cloneShallow() {
console.log(`[시스템] ${this.type} 얕은 복사 진행 중...`);
return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
}
// 깊은 복사(Deep Copy) 메서드 (참조 타입까지 복사)
cloneDeep() {
console.log(`[시스템] ${this.type} 깊은 복사 진행 중...`);
const cloned = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
// 배열을 새로 할당하여 참조를 분리
cloned.skills = [...this.skills];
return cloned;
}
status() {
console.log(`몬스터: ${this.type} / 체력: ${this.health} / 스킬: [${this.skills.join(', ')}]`);
}
}
// 📂 main.js
// 1. 최초 1회 원본(프로토타입) 생성 시에만 무거운 작업 수행
const ogrePrototype = new Monster("오우거", 100, ["몽둥이 휘두르기", "함성"]);
console.log("-------------------");
// 2. 이후 객체 생성은 얕은 복사를 통해 순식간에 이루어짐
const clonedOgre1 = ogrePrototype.cloneShallow();
const clonedOgre2 = ogrePrototype.cloneDeep();
// 3. 상태 변경 테스트
clonedOgre1.health = 50;
clonedOgre1.skills.push("발구르기"); // 얕은 복사라서 원본과 skills 배열을 공유해버림!
console.log("--- 얕은 복사의 부작용 ---");
ogrePrototype.status(); // 원본 오우거의 스킬에도 '발구르기'가 추가됨
clonedOgre1.status();
console.log("--- 깊은 복사는 안전함 ---");
clonedOgre2.health = 80;
clonedOgre2.skills.push("돌 던지기"); // 깊은 복사라서 배열이 독립적임
clonedOgre2.status();
ogrePrototype.status(); // 원본에는 '돌 던지기'가 없음