맨위로가기

프로토타입 패턴

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

프로토타입 패턴은 생성 패턴의 하나로, 객체를 복제하여 새로운 객체를 생성하는 방법을 제공한다. 이 패턴은 서브클래싱 없이 런타임에 객체를 생성하며, 복잡한 객체를 생성하는 비용을 줄여준다. 추상 팩토리 패턴, 빌더 패턴, 싱글톤 패턴 등 다른 생성 패턴과 함께 사용될 수 있으며, C++, C#, Java, Python, PHP 등 다양한 프로그래밍 언어에서 구현될 수 있다.

더 읽어볼만한 페이지

  • 소프트웨어 디자인 패턴 - 모델-뷰-컨트롤러
    모델-뷰-컨트롤러(MVC)는 소프트웨어 디자인 패턴으로, 응용 프로그램을 모델, 뷰, 컨트롤러 세 가지 요소로 분리하여 개발하며, 사용자 인터페이스 개발에서 데이터, 표현 방식, 사용자 입력 처리를 분리해 유지보수성과 확장성을 높이는 데 기여한다.
  • 소프트웨어 디자인 패턴 - 스케줄링 (컴퓨팅)
    스케줄링은 운영 체제가 시스템의 목적과 환경에 맞춰 작업을 관리하는 기법으로, 장기, 중기, 단기 스케줄러를 통해 프로세스를 선택하며, CPU 사용률, 처리량 등을 기준으로 평가하고, FCFS, SJF, RR 등의 알고리즘을 사용한다.
프로토타입 패턴
일반 정보
이름프로토타입 패턴
유형생성 디자인 패턴
목적기존 객체를 복제하여 새 객체를 생성
적용 시기객체 생성이 복잡하거나 비용이 많이 들 때
객체의 클래스를 런타임에 지정해야 할 때
객체의 상태 조합이 다양하고 복잡할 때
참여자Prototype (원형)
ConcretePrototype (구체적인 원형)
Client (클라이언트)
협업클라이언트는 원형으로부터 새로운 객체를 생성
결과복잡한 객체 생성 과정을 단순화
런타임에 객체의 종류를 변경 가능
객체 초기화 코드 중복 방지
관련 패턴추상 팩토리 패턴
빌더 패턴
팩토리 메서드 패턴
상세 정보
의도기존 객체를 복사하여 새로운 객체를 생성함으로써 객체 생성 과정을 단순화하고, 객체 초기화에 드는 비용을 줄인다.
동기객체 생성이 복잡하고 시간이 많이 소요될 때, 기존 객체를 복사하여 새로운 객체를 생성하는 것이 더 효율적일 수 있다.
특정 객체의 상태 조합이 매우 다양하고 복잡하여 일일이 객체를 생성하는 것이 번거로울 때, 기존 객체를 복사하여 원하는 상태로 변경하는 것이 더 간편할 수 있다.
활용성객체 생성이 복잡하거나 비용이 많이 들 때.
객체의 클래스를 런타임에 지정해야 할 때.
객체의 상태 조합이 다양하고 복잡할 때.
구조프로토타입 인터페이스를 정의하고, 이 인터페이스를 구현하는 구체적인 프로토타입 클래스를 생성한다. 클라이언트는 프로토타입 인터페이스를 통해 객체를 복사한다.
참가자Prototype (원형): 객체를 복제하는 인터페이스를 정의한다.
ConcretePrototype (구체적인 원형): Prototype 인터페이스를 구현하고, 자신을 복제하는 연산을 구현한다.
Client (클라이언트): Prototype 인터페이스를 통해 새로운 객체를 생성한다.
협력 방법클라이언트는 Prototype 인터페이스를 통해 객체를 복사한다. ConcretePrototype 클래스는 자신을 복제하는 연산을 구현하여 새로운 객체를 생성한다.
결과복잡한 객체 생성 과정을 단순화할 수 있다.
런타임에 객체의 종류를 변경할 수 있다.
객체 초기화 코드의 중복을 방지할 수 있다.
구현Prototype 인터페이스에 clone() 메서드를 정의한다.
ConcretePrototype 클래스에서 clone() 메서드를 구현하여 새로운 객체를 생성하고, 기존 객체의 상태를 복사한다.
샘플 코드 (C++)C++ 예제 코드
알려진 용도객체 생성을 캡슐화하고, 런타임에 객체의 종류를 변경하는 데 사용된다.
관련 패턴추상 팩토리 패턴: 객체 생성에 관련된 인터페이스를 제공한다.
빌더 패턴: 복잡한 객체를 단계별로 생성한다.
팩토리 메서드 패턴: 객체 생성 책임을 서브클래스로 넘긴다.
장점
유연성새로운 객체를 생성하는 방식을 런타임에 결정할 수 있다.
단순화복잡한 객체 생성 과정을 단순화할 수 있다.
효율성객체 초기화에 드는 비용을 줄일 수 있다.
단점
복잡성복사 생성자를 잘못 구현하면 예상치 못한 문제가 발생할 수 있다.
성능 문제깊은 복사를 수행하는 경우 성능 문제가 발생할 수 있다.

2. 역사적 배경

프로토타입 패턴은 구현, 변경, 테스트 및 재사용이 더 쉬운 객체인, 유연하고 재사용 가능한 객체 지향 소프트웨어를 설계하기 위해 반복적인 설계 문제를 해결하는 방법을 설명하는 23가지 GoF 디자인 패턴 중 하나이다.[1]

프로토타입 디자인 패턴은 다음과 같은 문제를 해결한다.


  • 특정 객체의 유형을 런타임에 결정할 수 있도록 객체를 어떻게 생성할 수 있는가?
  • 동적으로 로드된 클래스를 어떻게 인스턴스화할 수 있는가?


객체를 필요로 하는(사용하는) 클래스 내에서 직접 객체를 생성하는 것은 클래스를 컴파일 타임에 특정 객체에 고정시키고 런타임에 생성할 객체를 지정할 수 없게 하므로 유연하지 않다.

프로토타입 디자인 패턴은 이러한 문제를 해결하는 방법을 설명한다.

  • 자체 복사본을 반환하는 `Prototype` 객체를 정의한다.
  • `Prototype` 객체를 복사하여 새 객체를 생성한다.


이를 통해 다른 `Prototype` 객체로 클래스를 구성할 수 있으며, 이는 새 객체를 생성하기 위해 복사되고, 더 나아가 `Prototype` 객체는 런타임에 추가 및 제거될 수 있다.

3. 원칙

프로토타입 패턴은 "런타임"에 또 다른 "객체"를 생성하는 것을 원칙으로 한다. 즉, 이 시점에 클로닝(cloning)되는 객체의 "실제 복사본"이 만들어진다. "실제 복사본"은 새로 생성되는 객체가 클로닝 당하는 객체의 애트리뷰트와 동일한 애트리뷰트를 갖는다는 의미이다. 반면, "new"를 이용하여 객체를 생성하면 새로 생성된 객체의 애트리뷰트는 초기값을 갖는다.[7]

예를 들어, 은행 계좌 입출금 트랜잭션을 수행하는 시스템에서 프로그래머는 은행 이용자의 계좌 정보를 가진 객체를 복사하여 사용한다. 복사된 객체로 트랜잭션을 수행한 후 원래 객체를 대체하는 방식으로, new 대신 clone을 사용한다.[7]

프로토타입 디자인 패턴은 다음과 같은 문제를 해결한다.[7]


  • 특정 객체의 유형을 런타임에 결정할 수 있도록 객체를 어떻게 생성할 수 있는가?
  • 동적으로 로드된 클래스를 어떻게 인스턴스화할 수 있는가?


객체를 필요로 하는 클래스 내에서 직접 객체를 생성하는 것은 클래스를 컴파일 타임에 특정 객체에 고정시키고, 런타임에 생성할 객체를 지정할 수 없게 하므로 유연하지 않다.[7]

프로토타입 디자인 패턴은 이러한 문제에 대한 해결책으로 다음을 제시한다.[7]

  • 자체 복사본을 반환하는 `Prototype` 객체를 정의한다.
  • `Prototype` 객체를 복사하여 새 객체를 생성한다.


이를 통해 클래스를 다른 `Prototype` 객체로 구성할 수 있으며, 새 객체 생성을 위해 복사되고, 더 나아가 `Prototype` 객체는 런타임에 추가 및 제거될 수 있다.[7]

3. 1. 다른 생성 패턴과의 관계

객체 생성과 관련된 패턴들은 서로 겹치는 면이 있다. 추상 팩토리 패턴과 프로토타입 패턴 중 어느 하나가 적용될 수 있는 경우가 있다. 추상 팩토리 패턴이 프로토타입들의 집합을 갖고있다가, 클론(clone)한 뒤 프로덕트(product) 객체를 반환할 수도 있다.[7]

추상 팩토리 패턴, 빌더 패턴, 프로토타입 패턴은 각 구현에 있어서 싱글턴 패턴을 활용할 수 있다.[7][3]

추상 팩토리 클래스는 종종 팩토리 메서드와 함께 구현하거나[8], 프로토타입을 이용해서 구현되기도 한다.[9][4]

보통 설계는 처음에는 팩토리 메소드로 출발한다. 다음에 설계자의 재량에 따라 추상 팩토리 패턴, 빌더 패턴, 프로토타입 패턴으로 바뀔 수 있다.[7][5]

프로토타입은 서브클래싱을 필요로 하지 않는다. 하지만 "초기화" 동작을 필요로 한다. 팩토리 메서드 패턴은 서브클래싱을 필요로 하나, "초기화" 동작은 필요로 하지 않는다.[6]

컴포지트 패턴이나 데코레이터 패턴을 매우 많이 사용한 무거운 설계를 프로토타입을 사용하여 더 좋게 만들 수 있다.[2]

3. 2. 팩토리 메서드 패턴과의 비교

객체 생성 관련 패턴들은 서로 겹치는 면이 있다. 프로토타입 패턴과 추상 팩토리 패턴 중 어느 하나가 적용될 수 있는 경우가 있다. 추상 팩토리 패턴이 프로토타입 집합을 갖고 있다가, 클론한 뒤 프로덕트 객체를 반환할 수도 있다.[7]

추상 팩토리 패턴, 빌더 패턴, 프로토타입 패턴은 각 구현에서 싱글턴 패턴을 활용할 수 있다.[7][3]

추상 팩토리 클래스는 종종 팩토리 메소드와 함께 구현하거나[8], 프로토타입을 이용해서 구현하기도 한다.[9]

보통 설계는 처음에는 팩토리 메소드로 출발한다. 다음에 설계자 재량에 따라 추상 팩토리 패턴, 빌더 패턴, 프로토타입 패턴으로 바뀔 수 있다.[7][5]

프로토타입은 서브클래싱을 필요로 하지 않지만, "초기화" 동작은 필요로 한다. 팩토리 메서드 패턴은 서브클래싱을 필요로 하나, "초기화" 동작은 필요로 하지 않는다.[6]

컴포지트 패턴이나 데코레이터 패턴을 많이 사용한 무거운 설계를 프로토타입을 사용하여 더 좋게 만들 수 있다.[2]

4. 구조

프로토타입 디자인 패턴의 구조는 다음과 같다.

클래스 다이어그램시퀀스 다이어그램
프로토타입 디자인 패턴 UML 클래스 다이어그램
프로토타입 디자인 패턴 UML 클래스 및 시퀀스 다이어그램
`Client`는 `Product` 복제를 위해 `Prototype` 인터페이스를 참조한다. `Product1` 클래스는 자체 복사본을 만들어 `Prototype` 인터페이스를 구현한다.[1]`Client` 객체는 `prototype:Product1` 객체의 `clone()`을 호출하여 자체 복사본(`product:Product1` 객체)을 생성, 반환한다.[1]


4. 1. UML 클래스 다이어그램



위의 UML 클래스 다이어그램에서 `Client` 클래스는 `Product`를 복제하기 위해 `Prototype` 인터페이스를 참조한다. `Product1` 클래스는 자체 복사본을 생성하여 `Prototype` 인터페이스를 구현한다.[1]

UML 시퀀스 다이어그램은 런타임 상호 작용을 보여준다. `Client` 객체는 `prototype:Product1` 객체에서 `clone()`을 호출하여 자체 복사본(`product:Product1` 객체)을 생성하고 반환한다.[1]

4. 2. UML 시퀀스 다이어그램



UML 시퀀스 다이어그램은 런타임 상호작용을 보여준다. `Client` 객체는 `prototype:Product1` 객체에서 `clone()`을 호출하여 자체 복사본(`product:Product1` 객체)을 생성하고 반환한다.

5. 적용 사례

프로토타입 패턴은 객체 생성 시 유연성과 재사용성을 높이는 디자인 패턴 중 하나이다. 이 패턴은 특히 런타임에 객체의 유형을 결정하거나 동적으로 클래스를 인스턴스화해야 할 때 유용하다.

프로토타입 패턴은 다음과 같은 방식으로 작동한다.


  • 자신을 복사하여 반환하는 `Prototype` 객체를 정의한다.
  • `Prototype` 객체를 복사하여 새로운 객체를 생성한다.


이렇게 하면 클래스를 다른 `Prototype` 객체로 구성할 수 있으며, 런타임에 `Prototype` 객체를 추가하거나 제거할 수 있어 유연성이 높아진다.

예를 들어, 은행 계좌 거래 처리 시스템을 설계할 때, 계좌 정보 객체의 복사본을 만들고 거래를 수행한 후 복사본으로 원본 객체를 대체할 수 있다. 이때 `new` 대신 `clone()`을 사용하여 "진정한 복사본"을 생성하면 모든 속성이 복제된 객체를 얻을 수 있다.[2]

프로토타입 패턴은 추상 팩토리 패턴과 함께 사용될 수 있으며, 빌더 패턴, 싱글톤 패턴과 함께 구현될 수도 있다.[3][4] 또한, 컴포지트 패턴데코레이터 패턴을 많이 사용하는 디자인에도 유용하다.[5]

6. 예제

프로토타입 패턴은 생성할 객체의 종류를 프로토타입 인스턴스를 사용하여 지정하는 방식이다. 주로 새로운 객체의 프로토타입을 미리 만들어두지만, 아래 예시에서는 프로토타입이 복제에 직접 관여하지 않는다. 유사분열은 세포 분열을 통해 동일한 유전형을 가진 두 세포를 생성하는, 능동적인 자기 복제의 예시이다.[1]

```java

/**


  • 프로토타입 클래스
  • /

abstract class PrototypeFactory implements Cloneable {

public Object clone() throws CloneNotSupportedException {

// Object.clone() 호출

PrototypeFactory copy = (PrototypeFactory) super.clone();

// 실제 구현에서는 생성 비용이 큰 부분을 수정할 수 있음.

return copy;

}

abstract void prototypeFactory(int x);

abstract void printValue();

}

/**

  • 복제될 구체적인 프로토타입
  • /

class PrototypeImpl extends PrototypeFactory {

int x;

public PrototypeImpl(int x) {

this.x = x;

}

@Override

void prototypeFactory(int x) {

this.x = x;

}

public void printValue() {

System.out.println("Value :" + x);

}

}

/**

  • 클라이언트 클래스
  • /

public class PrototypeExample {

private PrototypeFactory example; // private Cloneable example일 수도 있음.

public PrototypeExample(PrototypeFactory example) {

this.example = example;

}

public PrototypeFactory makeCopy() throws CloneNotSupportedException {

return (PrototypeFactory) this.example.clone();

}

public static void main(String args[]) {

try {

PrototypeFactory tempExample = null;

int num = 1000;

PrototypeFactory prot = new PrototypeImpl(1000);

PrototypeExample cm = new PrototypeExample(prot);

for (int i = 0; i < 10; i++) {

tempExample = cm.makeCopy();

tempExample.prototypeFactory(i * num);

tempExample.printValue();

}

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

}

}

/*
코드 출력Value :0

Value :1000

Value :2000

Value :3000

Value :4000

Value :5000

Value :6000

Value :7000

Value :8000

Value :9000

  • /

6. 1. C++ 예제

cpp

#include

#include

#include

#include

using namespace std;

enum RECORD_TYPE_en

{

CAR,

BIKE,

PERSON

};

// Record는 프로토타입 역할을 한다.

class Record

{

public:

Record() {}

virtual ~Record() {}

virtual Record* Clone() const = 0;

virtual void Print() const = 0;

};

// CarRecord는 구체적인 프로토타입이다.

class CarRecord : public Record

{

private:

string m_oStrCarName;

uint32_t m_ui32ID;

public:

CarRecord(const string& _oStrCarName, uint32_t _ui32ID)

: Record(), m_oStrCarName(_oStrCarName),

m_ui32ID(_ui32ID)

{

}

CarRecord(const CarRecord& _oCarRecord)

: Record()

{

m_oStrCarName = _oCarRecord.m_oStrCarName;

m_ui32ID = _oCarRecord.m_ui32ID;

}

~CarRecord() {}

CarRecord* Clone() const

{

return new CarRecord(*this);

}

void Print() const

{

cout << "Car Record" << endl

<< "Name : " << m_oStrCarName << endl

<< "Number: " << m_ui32ID << endl << endl;

}

};

// BikeRecord는 구체적인 프로토타입이다.

class BikeRecord : public Record

{

private:

string m_oStrBikeName;

uint32_t m_ui32ID;

public:

BikeRecord(const string& _oStrBikeName, uint32_t _ui32ID)

: Record(), m_oStrBikeName(_oStrBikeName),

m_ui32ID(_ui32ID)

{

}

BikeRecord(const BikeRecord& _oBikeRecord)

: Record()

{

m_oStrBikeName = _oBikeRecord.m_oStrBikeName;

m_ui32ID = _oBikeRecord.m_ui32ID;

}

~BikeRecord() {}

BikeRecord* Clone() const

{

return new BikeRecord(*this);

}

void Print() const

{

cout << "Bike Record" << endl

<< "Name : " << m_oStrBikeName << endl

<< "Number: " << m_ui32ID << endl << endl;

}

};

// PersonRecord는 구체적인 프로토타입이다.

class PersonRecord : public Record

{

private:

string m_oStrPersonName;

uint32_t m_ui32Age;

public:

PersonRecord(const string& _oStrPersonName, uint32_t _ui32Age)

: Record(), m_oStrPersonName(_oStrPersonName),

m_ui32Age(_ui32Age)

{

}

PersonRecord(const PersonRecord& _oPersonRecord)

: Record()

{

m_oStrPersonName = _oPersonRecord.m_oStrPersonName;

m_ui32Age = _oPersonRecord.m_ui32Age;

}

~PersonRecord() {}

Record* Clone() const

{

return new PersonRecord(*this);

}

void Print() const

{

cout << "Person Record" << endl

<< "Name: " << m_oStrPersonName << endl

<< "Age : " << m_ui32Age << endl << endl;

}

};

// RecordFactory는 클라이언트 역할을 한다.

class RecordFactory

{

private:

map m_oMapRecordReference;

public:

RecordFactory()

{

m_oMapRecordReference[CAR] = new CarRecord("Ferrari", 5050);

m_oMapRecordReference[BIKE] = new BikeRecord("Yamaha", 2525);

m_oMapRecordReference[PERSON] = new PersonRecord("Tom", 25);

}

~RecordFactory()

{

delete m_oMapRecordReference[CAR];

delete m_oMapRecordReference[BIKE];

delete m_oMapRecordReference[PERSON];

}

Record* CreateRecord(RECORD_TYPE_en enType)

{

return m_oMapRecordReference[enType]->Clone();

}

};

int main()

{

RecordFactory* poRecordFactory = new RecordFactory();

Record* poRecord;

poRecord = poRecordFactory->CreateRecord(CAR);

poRecord->Print();

delete poRecord;

poRecord = poRecordFactory->CreateRecord(BIKE);

poRecord->Print();

delete poRecord;

poRecord = poRecordFactory->CreateRecord(PERSON);

poRecord->Print();

delete poRecord;

delete poRecordFactory;

return 0;

}

```

이 C++11 구현은 책에 있는 C++98 이전 구현을 기반으로 한다. 다형성 클래스 설계를 사용한 완전한 예제 구현과 함께 디자인 패턴에 대한 논의는 https://fbb-git.gitlab.io/cppannotations/cppannotations/html/cplusplus14.html#l318 C++ Annotations에서 제공된다.

```c++

#include

enum Direction {North, South, East, West};

class MapSite {

public:

virtual void enter() = 0;

virtual MapSite* clone() const = 0;

virtual ~MapSite() = default;

};

class Room : public MapSite {

public:

Room() :roomNumber(0) {}

Room(int n) :roomNumber(n) {}

void setSide(Direction d, MapSite* ms) {

std::cout << "Room::setSide " << d << ' ' << ms << '\n';

}

virtual void enter() {}

virtual Room* clone() const { // 자신을 복제하는 연산을 구현한다.

return new Room(*this);

}

Room& operator=(const Room&) = delete;

private:

int roomNumber;

};

class Wall : public MapSite {

public:

Wall() {}

virtual void enter() {}

virtual Wall* clone() const {

return new Wall(*this);

}

};

class Door : public MapSite {

public:

Door(Room* r1 = nullptr, Room* r2 = nullptr)

:room1(r1), room2(r2) {}

Door(const Door& other)

:room1(other.room1), room2(other.room2) {}

virtual void enter() {}

virtual Door* clone() const {

return new Door(*this);

}

virtual void initialize(Room* r1, Room* r2) {

room1 = r1;

room2 = r2;

}

Door& operator=(const Door&) = delete;

private:

Room* room1;

Room* room2;

};

class Maze {

public:

void addRoom(Room* r) {

std::cout << "Maze::addRoom " << r << '\n';

}

Room* roomNo(int) const {

return nullptr;

}

virtual Maze* clone() const {

return new Maze(*this);

}

virtual ~Maze() = default;

};

class MazeFactory {

public:

MazeFactory() = default;

virtual ~MazeFactory() = default;

virtual Maze* makeMaze() const {

return new Maze;

}

virtual Wall* makeWall() const {

return new Wall;

}

virtual Room* makeRoom(int n) const {

return new Room(n);

}

virtual Door* makeDoor(Room* r1, Room* r2) const {

return new Door(r1, r2);

}

};

class MazePrototypeFactory : public MazeFactory {

public:

MazePrototypeFactory(Maze* m, Wall* w, Room* r, Door* d)

:prototypeMaze(m), prototypeRoom(r),

prototypeWall(w), prototypeDoor(d) {}

virtual Maze* makeMaze() const {

// 프로토타입에게 자신을 복제하도록 요청하여 새 객체를 생성한다.

return prototypeMaze->clone();

}

virtual Room* makeRoom(int) const {

return prototypeRoom->clone();

}

virtual Wall* makeWall() const {

return prototypeWall->clone();

}

virtual Door* makeDoor(Room* r1, Room* r2) const {

Door* door = prototypeDoor->clone();

door->initialize(r1, r2);

return door;

}

MazePrototypeFactory(const MazePrototypeFactory&) = delete;

MazePrototypeFactory& operator=(const MazePrototypeFactory&) = delete;

private:

Maze* prototypeMaze;

Room* prototypeRoom;

Wall* prototypeWall;

Door* prototypeDoor;

};

// createMaze가 다양한 프로토타입 룸, 문, 벽 객체를 매개변수로 사용하고, 이를 복사하여 미로에 추가하는 경우, 이러한 프로토타입 객체를 다른 객체로 교체하여 미로의 구성을 변경할 수 있다. 이것은 프로토타입(133) 패턴의 예이다.

class MazeGame {

public:

Maze* createMaze(MazePrototypeFactory& m) {

Maze* aMaze = m.makeMaze();

Room* r1 = m.makeRoom(1);

Room* r2 = m.makeRoom(2);

Door* theDoor = m.makeDoor(r1, r2);

aMaze->addRoom(r1);

aMaze->addRoom(r2);

r1->setSide(North, m.makeWall());

r1->setSide(East, theDoor);

r1->setSide(South, m.makeWall());

r1->setSide(West, m.makeWall());

r2->setSide(North, m.makeWall());

r2->setSide(East, m.makeWall());

r2->setSide(South, m.makeWall());

r2->setSide(West, theDoor);

return aMaze;

}

};

int main() {

MazeGame game;

MazePrototypeFactory simpleMazeFactory(new Maze, new Wall, new Room, new Door);

game.createMaze(simpleMazeFactory);

}

```

프로그램 출력은 다음과 같다.

```c++

Maze::addRoom 0x1160f50

Maze::addRoom 0x1160f70

Room::setSide 0 0x11613c0

Room::setSide 2 0x1160f90

Room::setSide 1 0x11613e0

Room::setSide 3 0x1161400

Room::setSide 0 0x1161420

Room::setSide 2 0x1161440

Room::setSide 1 0x1161460

Room::setSide 3 0x1160f90

6. 2. C# 예제

csharp

public enum RecordType

{

Car,

Person

}

// Record는 프로토타입입니다.

public abstract class Record

{

public abstract Record Clone();

}

// PersonRecord는 구체적인 프로토타입입니다.

public class PersonRecord : Record

{

string name;

int age;

public override Record Clone()

{

return (Record)this.MemberwiseClone(); // 기본 얕은 복사

}

}

// CarRecord는 또 다른 구체적인 프로토타입입니다.

public class CarRecord : Record

{

string carname;

Guid id;

public override Record Clone()

{

CarRecord clone = (CarRecord)this.MemberwiseClone(); // 기본 얕은 복사

clone.id = Guid.NewGuid(); // 항상 새로운 id 생성

return clone;

}

}

// RecordFactory는 클라이언트입니다.

public class RecordFactory

{

private static Dictionary _prototypes = new Dictionary();

// 생성자

public RecordFactory()

{

_prototypes.Add(RecordType.Car, new CarRecord());

_prototypes.Add(RecordType.Person, new PersonRecord());

}

// 팩토리 메서드

public Record CreateRecord(RecordType type)

{

return _prototypes[type].Clone();

}

}

6. 3. Java 예제

java

/ Prototype Class /

public class Cookie implements Cloneable {

public Object clone() {

try {

Cookie copy = (Cookie) super.clone();

// 이 패턴의 실제 구현에서는 프로토타입 내부에 보관된 복사본에서

// 생성 비용이 많이 드는 부분에 대한 참조를 변경할 수 있습니다.

return copy;

} catch (CloneNotSupportedException e) {

e.printStackTrace();

return null;

}

}

}

/ Concrete Prototypes to clone /

class CoconutCookie extends Cookie {

}

/ Client Class /

class CookieMachine {

private Cookie cookie; // private Cloneable cookie;일 수도 있습니다.

public CookieMachine(Cookie cookie) {

this.cookie = cookie;

}

public Cookie makeCookie() {

return (Cookie) cookie.clone();

}



public static void main(String args[]) {

Cookie tempCookie = null;

Cookie prot = new CoconutCookie();

CookieMachine cm = new CookieMachine(prot);

for (int i = 0; i < 100; i++)

tempCookie = cm.makeCookie();

}

}

```

```java

/**

  • 프로토타입 클래스
  • /

abstract class PrototypeFactory implements Cloneable {

public Object clone() throws CloneNotSupportedException {

// Object.clone() 호출

PrototypeFactory copy = (PrototypeFactory) super.clone();

// 이 패턴의 실제 구현에서는 프로토타입 내부에 보관된 복사본에서

// 생성 비용이 많이 드는 부분에 대한 참조를 변경할 수 있습니다.

return copy;

}

abstract void prototypeFactory(int x);

abstract void printValue();

}

/**

  • 복제할 구체적인 프로토타입
  • /

class PrototypeImpl extends PrototypeFactory {

int x;

public PrototypeImpl(int x) {

this.x = x;

}

@Override

void prototypeFactory(int x) {

this.x = x;

}

public void printValue() {

System.out.println("Value :" + x);

}

}

/**

  • 클라이언트 클래스
  • /

class PrototypeExample {

private PrototypeFactory example; // private Cloneable example일 수도 있습니다.

public PrototypeExample(PrototypeFactory example) {

this.example = example;

}

public PrototypeFactory makeCopy() throws CloneNotSupportedException {

return (PrototypeFactory) this.example.clone();

}

public static void main(String args[]) {

try {

PrototypeFactory tempExample = null;

int num = 1000;

PrototypeFactory prot = new PrototypeImpl(1000);

PrototypeExample cm = new PrototypeExample(prot);

for (int i = 0; i < 10; i++) {

tempExample = cm.makeCopy();

tempExample.prototypeFactory(i * num);

tempExample.printValue();

}

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

}

}

/*

코드 출력

Value :0

Value :1000

Value :2000

Value :3000

Value :4000

Value :5000

Value :6000

Value :7000

Value :8000

Value :9000

  • /

6. 4. Python 예제

python

from copy import copy, deepcopy

class Prototype:

def __init__(self):

self._objs = {}

def registerObject(self, name, obj):

# 객체를 등록합니다.

self._objs[name] = obj

def unregisterObject(self, name):

# 객체 등록을 해제합니다.

del self._objs[name]

def clone(self, name, **attr):

# 등록된 객체를 복제하고 속성을 추가/변경합니다.

obj = deepcopy(self._objs[name])

obj.__dict__.update(attr)

return obj

# 예시 사용

class Graphic:

def clone(self):

return copy(self)

# 협력적이지 않은 형태

g = Graphic()

shallow_copy_of_g = copy(g)

deep_copy_of_g = deepcopy(g)

# 협력적인 형태

g2 = Graphic()

copy_of_g2 = g2.clone()

6. 5. PHP 예제

PHP 5에서는 객체가 참조(레퍼런스) 형태로 전달된다.[10] 값을 복사하여 전달하려면 "매직 펑션" `__clone()`을 사용해야 한다. 이러한 이유로 PHP 5에서는 프로토타입 패턴을 구현하기가 매우 쉽다.[10]

PHP 예제 코드:




abstract class BookPrototype {

protected $title;

protected $topic;

abstract function __clone();

function getTitle() {

return $this->title;

}

function setTitle($titleIn) {

$this->title = $titleIn;

}

function getTopic() {

return $this->topic;

}

}

class PHPBookPrototype extends BookPrototype {

function __construct() {

$this->topic = 'PHP';

}

function __clone() {

}

}

class SQLBookPrototype extends BookPrototype {

function __construct() {

$this->topic = 'SQL';

}

function __clone() {

}

}

writeln('BEGIN TESTING PROTOTYPE PATTERN');

writeln('');

$phpProto = new PHPBookPrototype();

$sqlProto = new SQLBookPrototype();

$book1 = clone $sqlProto;

$book1->setTitle('SQL For Cats');

writeln('Book 1 topic: '.$book1->getTopic());

writeln('Book 1 title: '.$book1->getTitle());

writeln('');

$book2 = clone $phpProto;

$book2->setTitle('OReilly Learning PHP 5');

writeln('Book 2 topic: '.$book2->getTopic());

writeln('Book 2 title: '.$book2->getTitle());

writeln('');

$book3 = clone $sqlProto;

$book3->setTitle('OReilly Learning SQL');

writeln('Book 3 topic: '.$book3->getTopic());

writeln('Book 3 title: '.$book3->getTitle());

writeln('');

writeln('END TESTING PROTOTYPE PATTERN');

function writeln($line_in) {

echo $line_in."
";

}

?>

[11]

위 코드의 출력 결과는 다음과 같다.[11]



BEGIN TESTING PROTOTYPE PATTERN

Book 1 topic: SQL

Book 1 title: SQL For Cats

Book 2 topic: PHP

Book 2 title: OReilly Learning PHP 5

Book 3 topic: SQL

Book 3 title: OReilly Learning SQL

END TESTING PROTOTYPE PATTERN


참조

[1] 간행물 Non-software examples of software design patterns Object Magazine 1997-07
[2] 서적 GoF
[3] 서적 GoF
[4] 서적 GoF
[5] 서적 GoF
[6] 서적 GoF
[7] 서적 디자인 패턴 (책)|Design Patterns Addison-Wesley
[8] 문서 상속 (객체 지향 프로그래밍)|상속
[9] 문서 딜리게이션
[10] 웹사이트 object cloning http://us2.php.net/m[...]
[11] 웹사이트 Prototype Design Pattern in PHP http://sourcemaking.[...]



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com