🎈 프로토타입 패턴 (Prototype Pattern)
• 객체 생성을 위해 다른 객체 복제
→ 새로운 객체 생성보다 기존 객체 복제하는 것이 효율적인 경우
→ 공통된 상태값은 유지, 필욯나 값만 변경
• 복잡한 과정으로 생성된 객체를 복사 생성할 때 유용
→ 재사용성 증가
• 별도로 원형 관리자를 도입해볼 수 있다.
그렇기에 객체 상태값을 접근/변경할 수 있도록 미리 구현 필요
• 디자인 패턴에서 생성 패턴 중 하나이다.
[예제 코드] 프로토타입 패턴
#include <iostream>
class Prototype {
public:
virtual Prototype* clone() = 0;
virtual void print() = 0;
virtual void setState(const std::string& state) = 0;
};
class ConcretePrototype : public Prototype {
private:
std::string state;
public:
ConcretePrototype() : state("") {}
ConcretePrototype(const ConcretePrototype& other) {
state = other.state;
}
Prototype* clone() override {
return new ConcretePrototype(*this);
}
void print() override {
std::cout << "상태: " << state << std::endl;
}
void setState(const std::string& newState) override {
state = newState;
}
};
void main() {
// 프로토타입 객체 생성
ConcretePrototype original;
// 원본 객체 상태 설정
original.setState("Original State");
// 프로토타입 객체 복제를 통해 새로운 객체 생성
Prototype* clone = original.clone();
// 복제 객체의 상태 설정
dynamic_cast<ConcretePrototype*>(clone)->setState("Cloned...");
original.print();
clone->print();
// 메모리 정리
delete clone;
}
예시에서는 하나의 상태만을 가지고 있지만
같은 상태로 복제되어 다른 속성 값을 가질 수 있는 것을 볼 수 있다.
[예제 코드] - 프로토타입 적용 X
#include <iostream>
#include <string>
class Knight {
private:
std::string name;
int health;
public:
Knight(const std::string& name, int health) : name(name), health(health) {}
void setName(std::string _name) {
name = _name;
}
void info() {
std::cout << "Knight: " << name << ", Health: " << health << std::endl;
}
};
void main() {
Knight k1("gga mang", 100);
Knight k2 = k1;
k2.setName("harbang");
k1.info();
k2.info();
}
C++의 복사생성자를 이용해서
프로토타입 패턴이 아니더라도 비슷하게 흉내낼 수 있다.
하지만 복제할 때, 복사생성자가 호출되는데
상태값이 바뀌는 런타임 중에 초기값과 이미 달라져 있을 수 있다.
[예제 코드] - 프로토타입 패턴 O
#include <iostream>
#include <string>
class Knight {
private:
std::string name;
int health;
public:
Knight(const std::string& name, int health) : name(name), health(health) {}
Knight* clone() {
return new Knight(*this);
}
void setName(std::string _name) {
name = _name;
}
void info() {
std::cout << "Knight: " << name << ", Health: " << health << std::endl;
}
};
void main() {
Knight originalKnight("gga mang", 100);
Knight* k1 = originalKnight.clone();
Knight* k2 = originalKnight.clone();
k2->setName("harbang");
k1->info();
k2->info();
}
🎈 프로토타입 패턴 장단점
+ 복잡한 객체 초기화 로직 처리에 유용하다.
+ 객체 생성을 위한 클래스의 수를 줄일 수 있다.
+ 유사한 구조나 초기 상태가 유사한 경우 좋다.
+ 객체 상태를 저장/복원해야 할 때, "스냅샷 용도"로도 좋다.
- 객체가 복제되는 것이기에 메모리 관리 필요
- 객체가 다른 객체와 상호 의존성을 가질 경우 복잡해질 수 있다.
[예제 코드]
#include <iostream>
#include <map>
#include <string>
class Unit {
public:
virtual Unit* clone() = 0;
virtual void render() = 0;
virtual void setState(const std::string& state) = 0;
};
class Knight : public Unit {
private:
std::string state;
public:
Knight(const std::string& initialState) : state(initialState) {}
Unit* clone() override {
return new Knight(*this);
}
Knight(const Knight& other) {
state = other.state;
}
void render() override {
std::cout << "Knight State: " << state << std::endl;
}
void setState(const std::string& newState) override {
state = newState;
}
};
class UnitFactory {
private:
std::map<std::string, Unit*> prototypes;
public:
UnitFactory() {
prototypes["Knight"] = new Knight("Default State");
}
Unit* createUnit(const std::string& type) {
return prototypes[type]->clone();
}
};
void main() {
UnitFactory factory;
Unit* knight1 = factory.createUnit("Knight");
Unit* knight2 = factory.createUnit("Knight");
// 주소 비교
if (knight1 != knight2) {
std::cout << "knight1과 knight2는 서로 다른 객체입니다." << std::endl;
}
// 상태 설정
dynamic_cast<Knight*>(knight1)->setState("1 First");
dynamic_cast<Knight*>(knight2)->setState("2 Second");
knight1->render();
knight2->render();
}
→ 서로 다른 Knight가 생성된 것을 확인할 수 있다.
→ 필요에 따라 속성 값을 변경할 수 있다.
🎈 다른 디자인 패턴과 비교
• 데코레이터 패턴
데코레이터 패턴은 객체에 동적으로 새로운 기능을 추가할 때 주료 사용한다.
상속을 사용하지 않고 기능 확장하는 것이 특징이다
싱글톤 패턴는 인스턴스를 오직 하나만 생성하고 전역 접근 지점을 제공한다.
즉, 하나의 객체를 다른 곳에서 공유할 때 사용된다.
반면에 프로토타입 패턴은 유사한 복사본을 만드는 것으로 여러 인스턴스를 복제 생성한다.
팩토리 패턴은 객체 생성을 캡슐화하여 생성 로직을 숨기는 패턴이다
이를 통해 다양한 클래스 객체를 생성한다.
유사한 객체를 복제하여 초기화하는 프로토타입 패턴과는 활용 차이가 있다.
복합 객체를 단계별로 설정할 때 사용되는 패턴으로
복잡하게 만들어진 객체를 복제할 때 프로토타입 활용 하면 좋다.
심지어 기존 객체 생성을 몰라도 된다.
'까망 동네 > 디자인 패턴' 카테고리의 다른 글
[디자인패턴] 커맨드 패턴 (Command Pattern) (1) | 2023.11.03 |
---|---|
[디자인패턴] 장식자 패턴 (Decorator) (2) | 2023.11.01 |
[디자인 패턴] 브릿지 패턴 (Bridge Pattern) (3) | 2023.10.28 |
[디자인 패턴] 중재자 패턴 (Mediator Pattern) (0) | 2023.10.22 |
[디자인 패턴] 빌더 패턴 (Builder Pattern) (2) | 2023.10.21 |
댓글