프로토타입 패턴(Prototype Pattern)#
- 객체를 생성하는 방법은
new
키워드를 사용한 방법이 일반적입니다.C++
의 스마트 포인터도 내부적으로 new
키워드를 사용합니다.
- 객체를 생성하는 또 한가지 방법은 객체를 복사(Copy)하는 방법입니다.
- 프로토타입 패턴은 객체를 복사하는 방법을 사용하여 객체를 생성합니다.
프로토타입 패턴의 구조#
- 프로토타입 패턴은 신규 객체를 생성하지 않고, 기존에 만들어진 객체를 복제합니다.
C++
에서 객체를 복사하는 방법은 얕은 복사(Shallow Copy
)와 깊은 복사(Deep Copy
)가 있습니다.- 프로토타입 패턴은 특별한 구조를 갖는 것이 아니라, 복사를 활용합니다.
프로토타입 패턴을 위한 예제#
- 사용자가 지정한 메세지를 객체가 저장하고 있다가 필요할때 반환하는 클래스를 작성합니다.
class Hello
{
public:
Hello(const std::string& message)
{
m_message = message;
}
void setMessage(const std::string& message)
{
m_message = message;
}
const std::string& getMessage()
{
return m_message;
}
private:
std::string m_message;
};
얕은 복사(Shallow Copy)#
- 객체 복사는 일반적인 대입연산자(
=
)를 사용합니다. - 얕은 복사는 객체를 복사하더라도, 객체가 갖고 있는 변수들을 공유합니다.
- 변수를 공유한다는 것은 불필요한 메모리를 할당하지 않고, 자원을 절약하는 방법입니다.
얕은 복사 예제 실행 코드#
- 간단한 예제를 작성하고 실행 결과를 살펴봅니다.
int main(const int argc, const char* argv[])
{
std::shared_ptr<Hello> korea = std::make_shared<Hello>("Hello Korea");
korea->setMessage("Hello Korea");
std::cout << "Original message: " << korea->getMessage() << std::endl;
// Shallow copy
std::shared_ptr<Hello> english = korea;
english->setMessage("Hello English");
std::cout << "After shallow copied original message: " << korea->getMessage() << std::endl;
std::cout << "english message: " << english->getMessage() << std::endl;
return 0;
}
Original message: Hello Korea
After shallow copied original message: Hello English
english message: Hello English
- 대입연산자(
=
)로 객체를 복사하고 setMessage()
메서드로 프로퍼티의 값을 변경했습니다. - 원본 객체인
korea
의 프로퍼티 또한 변경된 것을 확인할 수 있습니다. - 이처럼 얕은 복사는 불필요한 메모리의 확장을 방지합니다.
깊은 복사(Deep Copy)#
- 깊은 복사는 객체를 복제할 경우 내부 프로퍼티를 공유하지 않습니다.
- 프로토타입 인터페이스 클래스를 설계합니다.
- 복제한 대상 객체들의 공통 인터페이스인
setMessage()
와 getMessage()
를 추가로 선언하였습니다. clone()
메서드의 반환형은 구현하는 타입에 따라 다르게 설정할수 있습니다.
class Prototype
{
public:
virtual std::shared_ptr<Prototype> clone() const = 0;
virtual void setMessage(const std::string& message) = 0;
virtual const std::string& getMessage() = 0;
};
- 이어서
Prototype
을 상속하는 클래스인 Hello
도 다시 수정합니다.
class Hello :
public Prototype
{
public:
Hello(const std::string& message)
{
m_message = message;
}
void setMessage(const std::string& message)
{
m_message = message;
}
const std::string& getMessage()
{
return m_message;
}
std::shared_ptr<Prototype> clone() const override
{
return std::make_shared<Hello>("");
}
private:
std::string m_message;
};
깊은 복사 예제 실행 코드#
- 예제 코드를 작성해보고 얕은 복사와 결과가 어떻게 다른지 확인합니다.
int main(const int argc, const char* argv[])
{
std::shared_ptr<Prototype> korea = std::make_shared<Hello>("Hello Korea");
korea->setMessage("Hello Korea");
std::cout << "Original message: " << korea->getMessage() << std::endl;
// deep copy
auto english = korea->clone();
english->setMessage("Hello English");
std::cout << "After shallow copied original message: " << korea->getMessage() << std::endl;
std::cout << "english message: " << english->getMessage() << std::endl;
return 0;
}
Original message: Hello Korea
After shallow copied original message: Hello Korea
english message: Hello English
clone()
을 사용할 경우 원본 객체의 프로퍼티가 변경되지 않습니다.- 이는 원본 객체와 복제한 객체가 갖는 프로퍼티가 다른 공간에 메모리가 할당되었음을 의미합니다.