프로그래밍/C++ 이용한 디자인패턴

Composite(컴포지트) 패턴 with C++

친루엄 2018. 4. 16. 22:15

[ Composite 패턴이란.]

어떤 객체의 구성원(맴버변수)들이 동적으로 결정될 때 이 객체를 생성, 관리할 수 있으면서도 기본객체(정적)와 구성객체(동적)를 구분없이 사용할 수 있고 기본 객체 뿐만 아니라 구성 객체도 또 다른 구성객

체의 구성원이 될 수 있게 만들어진 클래스 구조이다..이런 형태는 재귀적인 구조로서, 마치 파일 구조에서 디렉토리 안에 파일이 존재할 수도 있고, 또 다른 디렉토리가 존재할 수 있는 것과 같다.

 

[ Composite 패턴을 써야할 상황 예.]

우리가 그림판을 구현한다고 해보자. 그림판는 여러가지 기본모양들을 지원한다. 예를 들어 사각형을 그리고 싶으면 메뉴에서 사각형을 클릭하여 마우스로 그리면 된다.  그런데 사용자가 동적으로 모양을 추가 하고 싶다고 한다 예를 들어 사각형과 삼각형을 만든 집모양을 그림판에 기본모양으로 추가하고싶다고한다.  집모양을 계속 만들고 싶을때 기본 도형들을 일일이 선택해서 복사하기는 무리가 있다. 

이럴땐 어떻게 구현을 해야하겠는가?

 

 [ Composite 패턴 샘플 소스코드.]

 

   
#include <iostream>
#include <list>
#include <iterator>
#include <map>
using namespace std;

class Graphic
{
public:
	virtual void Draw() = 0;
	virtual void Add(Graphic* pObj) {}
	virtual void Remove(Graphic* pObj) {}
	virtual Graphic* GetChild(int nth) { return 0; }
};

//삼각형 기본객체
class Triangle : public Graphic
{
public:
	void Draw() {}
};

//사각형 기본객체
class Rectangle : public Graphic
{
public:
	void Draw() {}
};

//동적모형 객체
class ComposedGraphic : public Graphic
{
private:
	list components_;

public:
	void Draw()
	{
		for (Graphic* gp : components_)
			gp->Draw();
	}

	void Add(Graphic *pObj)
	{
		components_.push_front(pObj);
	}

	void remove(Graphic *pObj)
	{
		list<Graphic*>::iterator iter1;
		for (iter1 = components_.begin(); iter1 != components_.end(); iter1++)
		{
			if (*iter1 == pObj)
				components_.erase(iter1);
		}
	}

	Graphic* GetChild(int nth)
	{
		int i;
		list<Graphic*>::iterator iter1;
		for (i = 0, iter1 = components_.begin();
			iter1 != components_.end(); iter1++, i++)
		{
			if (i == nth) return *iter1;
		}
		return 0;
	}
};

class Palette
{
private:
	map<int,Graphic*> items_;
public:
	Palette()
	{
		Graphic* pGraphic = new Triangle;
		items_[1] = pGraphic;

		pGraphic = new Rectangle;
		items_[2] = pGraphic;

		// -- 필요한 만큼 기본 도형 등록
	}

	void RegisterNewGraphic(Graphic* pGraphic)
	{
		items_[items_.size() + 1] = pGraphic;
	}
};

int main()
{
	Triangle aTriangle;
	Rectangle aRectangle;
	ComposedGraphic aComposedGraphic2;

	aComposedGraphic2.Add(&aTriangle);
	aComposedGraphic2.Add(&aRectangle);

	Rectangle aRectangle2;
	ComposedGraphic aComposedGraphic;

	aComposedGraphic.Add(&aComposedGraphic2);
	aComposedGraphic.Add(&aRectangle2);
}

 

ComposedGraphic 클래스는 Graphic의 하위 클래스로 정의 되어 있으며 내부 데이터 맴버로 Grphic 클래스 객체에 대한 포인터 변수를 리스트로 저장,관리 할 수 있다. 또한 ComplsedGraphic 클래스는 동적으로 정의되는 구성원 객체를 추가 삭제할 수 있도록 하기위해 Add(),Remove()맴버 함수도 제공한다. 이 밖에 Composed Graphic 클래스는 외부에서 원할 경우 객체를 구성하는 세부 객체들을 찾아볼 수 있게 GetChild() 맴버 함수도 제공한다.

 

[ Composite 패턴의 일반적인 클래스 구조.]

출처

http://terms.naver.com/entry.nhn?docId=3532964&cid=58528&categoryId=58528

 

[ Composite 패턴의 유용한 경우]

 1. 객체들간에 부분 - 전체 관계가 있고 이를 표현하고자 할때

 2. 개별 객체와 개별 객체들로 구성된 객체가 공존하는 상황에서 Cilent는 이들을 서로

     구분하지 한고 동일한 형태로 객체들을 다루고 싶을때.

 

[ Composite 패턴의 장단점]

장점

1. 사용자 입정에서는 기본객체와 구성 객체를 특별히 구별하지 않고 소스코드를 작성 할 수 있기 때문에

   편히라다. 이는 기본객체와 구성객체가 동일한 클래스 상속 구조 내에 정의되어 동일한 자료형으로 표

   현이 가능하기 때문이다.

2. 새로운 클래스의 추가가 용이하다. 왜냐하면 새로운 클래스를 추가하더라도 기존의 사용자 소스코드

   는 변경될 필요가 없기 때문이다. 최상위 클래스는 하위클래스들이 필요로 하는 모든 인터페이스를

   정의하고 있기 때문에 사용자 소스코드가 최상위 클래스 자료형만으로도 작성 될 수 있기 때문이다.

단점

   전반적으로 설계를 일반화시킨다. 이런 점은 특정 Component 객체로만 Composite 객체를 구성하고

   싶을 경우에는 문제가 될 수 있다. 예를 그림판에서 새로운 도형을 정의할 때 사각형이나 삼각형만

   조합할 수 있고  다른 도형은 조합을 못한다고 하자. 그럼 이미 추가된 도형에서 사각형이나 삼각형

   말고 다른 도형이 추가 됬는지 일일이 점검하는 수밖에 없다.