본문 바로가기
SW

GoF의 디자인 패턴(Design Patterns: Elements of Reusable Object-Oriented Software) - 3장 생성 패턴 :: 원형(Prototype)

by 라꾸스떼(YR) 2020. 4. 21.
반응형

[원형(Prototype) - 객체생성]

<의도>

원형이 되는 인스턴스를 사용하여 생성할 객체의 종류를 명시하고, 이렇게 만든 견본을 복사해서 새로운 객체를 생성한다.

 

<동기>

GraphicTool 클래스는 프레임워크 설계자에게 문제를 일으킬 수 있다. 음표와 보표에 대한 클래스는 지금 개발할 응용프로그램에만 국한된 것이고, GraphicTool 클래스는 범용적인 프레임워크에 속해있는 것이다. 즉, 이러한 GraphicTool은 악보에 추가할 음악 클래스들의 인스턴스를 어떻게 생성해야 하는지 알지 못한다. 이런 이유로 응용프로그램에서 필요한 음악 객체를 각각 생성하려면 GraphicTool을 상속받는 새로운 서브클래스를 만들어야 한다. 그러나 이렇게 되면 인스턴스화해야 하는 각 음악 객체 종류마다 여러 가지 다른 서브클래스를 만들어야 한다. 객체 합성이 서브클래싱의 문제를 해결하는 또 다른 방법이다. 문제는 프레임워크가 어떻게 복합을 이용하여, 프레임워크가 생성해야 하는 Graphic 클래스로 GraphicTool 클래스의 인스턴스를 매개변수화할 수 있는가 하는 것이다.

이를 해결할 수 있는 방법은 GraphicTool 클래스가 Graphic 서브클래스의 인스턴스를 복제(cloning)함으로써 새로운 Graphic 인스턴스를 만들도록 하는 것이다. 이렇게 복제된 인스턴스를 원형이라고 한다. GraphicTool은 자신이 복제해야 할 원형으로 매개변수화되며 문서에 추가된다.

원형 패턴을 사용하면 클래스 수를 줄일 수 있다. 클래스는 동일하게 하고, 안에 정의될 값이나 구조를 달리하는 좋은 방법이다.

 

<활용성>

원형 패턴은 제품의 생성, 복합, 표현 방법에 독립적인 제품을 만들고자 할 때 쓴다.

-인스턴스화할 클래스를 런타임에 지정할 때(동적 로딩)

-제품 클래스 계통과 병렬적으로 만드는 팩토리 클래스를 피하고 싶을 때

-클래스의 인스턴스들이 서로 다른 상태 조합 중에 어느 하나일 때 원형 패턴을 쓴다. 이들을 미리 원형으로 초기화해 두고, 나중에 이를 복제해서 사용하는 것이 매번 필요한 상태 조합의 값들을 수동적으로 초기화하는 것보다 더 편리할 수 있다.

 

<참여자>

-Prototype : 자신을 복제하는데 필요한 인터페이스를 정의

-ConcretePrototype : 자신을 복제하는 연산을 구현

-Client : 원형에 자기 자신의 복제를 요청하여 새로운 객체를 생성

 

<협력 방법>

사용자는 원형 클래스에 스스로를 복제하도록 요청한다.

 

<결과>

원형 패턴은 추상 팩토리 및 빌더와 비슷한 결과를 갖는다.

1.런타임에 새로운 제품을 추가하고 삭제할 수 있다. 사용자에게 원형으로 생성되는 인스턴스를 등록하는 것만으로도 시스템에 새로운 제품 클래스를 추가할 수 있게 된다. 런타임에 새로운 원형을 넣고 빼기가 쉽다는 점에서 다른 생성 패턴에 비해 유연성을 지니고 있다.

2.값들을 다양화함으로써 새로운 객체를 명세한다. 사용자와 동작할 원형에 해당하는 기존 클래스의 인스턴스를 만들어서 그 인스턴스를 등록하면, 사용자는 이 원형에 정의된 행동이 수행되어 마치 새로운 행동이 정의된 듯한 결과를 얻게 된다.

3.구조를 다양화함으로써 새로운 객체를 명세할 수 있다.

4.서브클래스의 수를 줄입니다. 팩토리 메서드를 보면 Creator 클래스의 계통이 처리할 제품 관련 클래스의 계통과 병렬로 복합되는 것을 알 수 있다. 원형 패턴에서는 팩토리 메서드에 새로운 객체를 만들어 달라고 요청하는 것이 아니라 원형을 복제하는 것이므로, Creator 클래스에 따른 새로운 상속 계층은 필요 없다.

5.동적으로 클래스에 따라 응용프로그램을 설정할 수 있다. 동적으로 로드된 클래스의 인스턴스를 생성하고 싶은 응용프로그램은 정적으로 그 클래스의 생성자를 참조할 수 없다. 그 대신 런타임 환경이 그 클래스의 인스턴스를 자동으로 생성하고 원형 관리자에게 등록한다. 그러면 응용프로그램은 이 원형 관리자에게서 필요한 클래스의 인스턴스를 얻게 된다.

원형 패턴을 쓸 때 가장 큰 걸림돌은 원형의 서브클래스가 Clone() 연산ㅇ을 구현해야 한다는 것이다. 복사를 지원하지 않거나 환형 참조(Circular Reference)가 없는 객체를 포함한다면 Clone() 연산의 구현은 어려울 수 있다. 이런 때는 원형 패턴 적용이 힘들다.

 

<구현>

1.원형 관리자를 사용한다. 원형의 수가 아직 정해지지 않은 때라면 가능한 원형이 등록된 레지스트리를 관리해야 한다. 사용자는 원형을 복제하기 전에 레지스트리에 원형이 있는지 먼저 알아본다. 이런 레지스트리를 가리켜 원형 관리자(Prototype Manager)라고 한다. 원형 관리자는 어떤 키에 부합되는 원형을 저장하고, 찾아서 반환하며, 또 삭제하는 기능을 담당하는 저장소이다.

2.Clone() 연산을 구현한다. Clone() 연산을 구현할 때는 무엇을 복사하고, 무엇을 공유하도록 할 것인지 결정해야 한다.

3.Clone을 초기화한다. Clone() 연산에 매개변수를 정의하게 되면 복제 인터페이스의 일관성이 없어진다. Initialize() 등의 이름을 가진 연산을 사용자에게 제공해야 한다. 이 연산은 초기화 매개변수를 인자로 받아 그 복제본의 내부 상태를 설정한다. 깊은 복사를 수행하는 Clone 연산이 있다는 점도 유념해야 한다.

 

<예제 코드>

사용자가 구체적인 서브클래스를 몰라도 원형을 복제할 수 있도록 해야 한다는 것이다. 사용자는 Clone() 연산의 반환 값을 자신이 원하는 타입으로 다운캐스트할 필요가 절대로 없어야 한다.

 

<잘 알려진 사용예>

-

 

<관련 패턴>

원형 패턴과 추상 팩토리 패턴은 어떤 면에서는 경쟁적인 관계다. 하지만 함께 사용될 수도 있다. 추상 팩토리 패턴은 원형 집합을 저장하다가 필요할 때 복제하여 제품 객체를 반환하도록 사용할 수도 있다. 만약 복합체 패턴과 장식자 패턴을 많이 사용해야 하는 설계에서 원형 패턴을 쓰면 종종 많은 재미를 볼 수 있다.

반응형

댓글