참조: Java 언어로 배우는 디자인 패턴 입문

"복사해서 인스턴스 만들기"
"클래스에서 인스턴스를 만들지 않고 인스턴스에서 인스턴스 만들기"

객체를 클래스를 사용하여 new로 생성하지 않고 복사해서 만들고 싶은 경우
- 취급하는 객체가 다양해서 각각을 별도의 클래스로 두기엔 무리가 있을 때..
- 클래스에서 객체 생성이 어려운 경우(ex. 런타임에 마우스 조작으로 만들어 내는 객체)
- 프레임워크와 생성할 인스턴스를 분리하고 싶을 때. 모형이 되는 객체를 등록해 놓고 그 객체를 복사해서 인스턴스 생성.

예제 코드 from Wikipedia

/** Prototype Class **/
public class Cookie implements Cloneable {

public Object clone() {
try {
Cookie copy = (Cookie)super.clone();

//In an actual implementation of this pattern you might now change references to
//the expensive to produce parts from the copies that are held inside the prototype.

return copy;

}
catch(CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}

/** Concrete Prototypes to clone **/
public class CoconutCookie extends Cookie { }

/** Client Class**/
public class CookieMachine {

private Cookie cookie;//could have been a 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();
}
}

Prototype
- 원형 인터페이스로 객체 복사에 사용할 메소드를 정의한다.
- Cloneable 인터페이스 상속.

ConcretePrototype
- Prototype 인터페이스 구현하여 실제 복사 로직 구현.

Client
- Prototype 인터페이스를 사용하여 새로운 객체를 만든다.

주의할 것.
- Cloenable은 마커 인터페이스.
- 실제 clone 메소드는 Object 클래스에 들어있다.
- 필드 대 필드 복사라서 배열의 경우 레퍼런스를 복사해서 위험할 수 있다. 그럴 땐 직접 clone 메소드를 재정의 해야 한다.
- clone을 재정의 할 떄는 super.clone()을 호출해야 한다.
- clone은 복사만 하지 생성자를 호출하지 않는다. 그래서 생성시에 로직이 필요한 땐 그 로직도 clone에 같이 넣어 준다.
- 자세한건 API를 보시라...