관련 영상
프로토타입 패턴
위키피디아
설명 및 스도코드
- 코드를 그들의 클래스들에 의존시키지 않고 기존 객체들을 복사할 수 있도록 하는 생성 디자인 패턴
- 생성할 객체들의 타입이 프로토타입인 인스턴스로부터 결정되도록 하며, 인스턴스는 새 객체를 만들기 위해 자신을 복제(clone)하게 된다
프로토타입 패턴의 구조
- 프로토타입 인터페이스(Prototype Interface)
- 복제 메서드들을 선언하며 이 메서드들의 대부분은 단일
clone()
메서드이다
- 구상 프로토타입(Concrete Prototype)
- 복제 메서드를 구현한다.
- 원본 객체의 데이터를 복제본에 복사하는 것 외에도 이 메서드는 복제 프로세스와 관련된 일부 예외적인 경우들도 처리할 수 있다.
- 클라이언트
- 프로토타입 인터페이스를 따르는 모든 객체의 복사본 생성 가능
- 프로토타입 레지스트리(Prototype Registrt)
- 자주 사용하는 프로토타입들에 쉽게 접근하는 방법 제공
- 복사될 준비가 된 미리 만들어진 객체들의 집합을 저장함
- 가장 간단한 프로토타입 레지스트리는 name->prototype 해시맵
프로토타입의 적용
- 복사하는 객체들의 구상 클래스들에 코드가 의존하면 안될 때
- 이와 같은 경우는 코드가 어떤 인터페이스를 통해 타사 코드에서 전달된 객체들과 함께 작동할 때 많이 발생함
- 프로토타입 패턴은 클라이언트 코드에 복제를 지원하는 모든 객체와 작업할 수 있도록 일반 인터페이스를 제공. 이 인터페이스는 클라이언트 코드가 복제하는 객체들의 구상 클래스들에서 클라이언트 코드를 독립시킨다.
- 각자의 객체를 초기화하는 방식만 다른 자식 클래스들의 수를 줄이고 싶을 때 사용
- 프로토타입 패턴은 다양한 방식으로 설정된 미리 만들어진 객체들의 집합을 프로토타입들로 사용할 수 있도록 한다. 일부 설정과 일치하는 자식 클래스를 인스턴스화하는 대신 클라이언트는 간단하게 적절한 프로토타입을 찾아 복제할 수 있다.
다른 패턴과의 관계
- 많은 디자인은 복잡성이 낮고 자식 클래스들을 통해 더 많은 커스터마이징이 가능한 팩토리 메서드로 시작해 더 유연하면서도 더 복잡한 추상 팩토리, 프로토타입 또는 빌더 패턴으로 발전해 나간다.
- 추상 팩토리 클래스들은 팩토리 메서드들의 집합을 기반으로 하는 경우가 많다. 그러나 프로토타입을 사용하여 추상 팩토리의 구상 클래스들의 생성 메서드들을 구현할 수도 있다.
- 프로토타입은 커맨드 패턴의 복사본들을 기록에 저장해야 할 때 도움이 될 수 있다.
- 데코레이터 및 복합체 패턴을 많이 사용하는 디자인들은 프로토타입을 사용하면 종종 이득을 볼 수 있다. 프로토타입 패턴을 적용하면 복잡한 구조들을 처음부터 다시 건축하는 대신 복제할 수 있기 때문
- 프로토타입은 상속을 기반으로 하지 않으므로 상속과 관련된 단점들이 없다. 반면에 프로토타입은 복제된 객체의 복잡한 초기화가 필요하다. 팩토리 메서드는 상속을 기반으로 하지만 초기화 단계가 필요하지 않다.
- 때로는 프로토타입이 메멘토 패턴의 더 간단한 대안이 될 수 있으며, 이 패턴은 상태를 기록에 저장하려는 객체가 간단하고 외부 리소스에 대한 링크가 없거나 링크들이 있어도 이들을 재설정하기 쉬운 경우에 작동한다.
- 추상 팩토리들, 빌더들 및 프로토타입들은 모두 싱글턴으로 구현할 수 있다.
유니티로 구현한 유닛 클론 소환
public interface IUnit
{
// Method for cloning
IUnit Clone();
}
- 콘크리트 프로토타입
MemberwiseClone()
함수는 얕은 복사로 단순 복사본 객체를 생성해 리턴하는 함수
// 'ConcretePrototype1' class implements IPrototype interface
public class Marine : IUnit
{
public int Hp { get; set; }
public int AttackPower { get; set; }
// Implement shallow cloning method
public IUnit Clone()
{
// Shallow Copy
return this.MemberwiseClone() as IUnit;
// Deep Copy
// Implement Memberwise clone method for every reference type object
// return ..
}
}
public class Firebat : IUnit
{
public int Age { get; set; }
public int AttackPower { get; set; }
// Implement shallow cloning method
public IUnit Clone()
{
// Shallow Copy
return this.MemberwiseClone() as IUnit;
}
}
public class UnitManager : MonoBehaviour {
void Start () {
Marine marine = new Marine();
marine.Hp = 25;
marine.AttackPower = 5;
// clone Marine object with Clone method
// If you will not set the new value for any field the it will take the default value
// from original object
Marine marineClone = (Marine)marine.Clone();
marineClone.Hp = 30; // 값만 수정해준다.
marineClone.AttackPower = 6; // 값만 수정해준다.
Debug.Log("Marine Details");
Debug.LogFormat("Age: {0} / AttackPower: {1}",marine.Hp, marine.AttackPower);
Debug.Log("Cloned Marine Details");
Debug.LogFormat("Age: {0} / AttackPower: {1}", marineClone.Hp, marineClone.AttackPower);
// you can perform the same operation for Firebat
}
}