프로그래밍 기술/Escort GoF의 디자인 패턴

8. 복합체 패턴(Composite Pattern) [Escort GoF의 디자인 패턴]

언제나휴일 2016. 4. 4. 13:54
반응형

8. 복합체 패턴(Composite Pattern)

 

8.1 개요

 

 복합체 패턴은 복합 개체와 단일 개체를 같은 방법으로 사용하고자 할 때 사용되는 패턴입니다. 복합체 패턴은 트리 구조로 관리고자 할 때 자주 사용이 됩니다. 예로 폴더(복합 개체)와 파일(단일 개체)을 같은 방법으로 사용하게 하는 것이죠.

 

 이처럼 복합체 패턴에서는 단일 개체와 복합 개체를 같은 방법으로 사용할 수 있게 일반화하여 기반 클래스를 제공합니다. 단일 개체 형식과 복합 개체 형식은 파생된 클래스로 구현하겠죠. 중요한 것은 기반 클래스에서 단일 개체와 복합 개체에서 할 수 있는 모든 기능을 인터페이스로 약속한다는 점에 있습니다. 이를 통해 사용자는 해당 개체가 단일 개체인지 복합 개체인지를 모르더라도 같은 방법으로 사용할 수 있는 것입니다.

 

 하지만 이와 같은 복합체 패턴에서는 실제 개체 형식에서는 아무 필요도 없는 기능까지 기반 클래스에서 제공하는 단점을 갖게 됩니다. , 사용자에게 같은 방법으로 사용할 수 있게 한다는 이점을 주는 대신 의미 없는 행동에 대한 메서드도 비어있는 상태로 제공해야 한다는 단점을 갖고 있습니다.

 

 이와 같은 복합체 패턴을 사용하면 다양한 종류의 단일 개체 형식을 추가하는 것이 쉽습니다. 반면, 특정 복합 개체에 포함할 수 있는 개체의 형식에 제한을 줄 필요성이 있을 때는 프로그램이 동작하는 실행 시간에 실제 개체 형식을 참조하여 처리해야 하는 비용이 들게 됩니다.

 

 사용자에게 같은 방법으로 접근할 수 있게 투명성을 제공할 것인지 불필요한 행위를 제공하지 않음으로써 안정성을 택할 것인지는 개발자의 선택사항입니다. 안정성보다 투명성을 제공하는 것이 이득이 많다고 판단되면 복합체 패턴을 사용하시기 바랍니다.

 

 

 

 

 

8. 2 시나리오

 

 매주 주말에 여행을 다니다 보니 사진이 제법 많아졌습니다. 그러다 보니 제가 원하는 사진을 찾는 게 힘들어지고 있어요. 지역 단위로 폴더 이름을 정하면 특정 날짜에 찍은 사진을 찾는 것이 불편하고 날짜 단위로 폴더 이름을 정하면 지역으로 검색하는 것이 불편하고 이 외에도 자연을 찍은 것만 찾고 싶거나 가족사진을 찾고 싶거나 할 때 찾기가 어렵더군요. 그렇다고 같은 사진을 여러 폴더에 복사하여 관리하는 것도 불편하고요.

 

 이번에는 좀 더 검색이 쉬운 응용 프로그램을 작성해 보려고 합니다. 필요하면 카테고리를 추가하고 각 카테고리에는 서브 카테고리나 사진이 있는 절대 경로를 보관할 거예요.


복합체 패턴



AboutComposite.zip



//common.h

#pragma once

 

#pragma warning (disable:4996)

#include <iostream>

 

using std::cout;

using std::endl;

#include <vector>

using std::vector;

#include <string>

using std::string;

 

#include <iomanip>

using std::ios;

#include <algorithm>

 

//Tree.h

#pragma once

 

#include "common.h"

 

class Tree

{           

             Tree *parent;         

             const string name;

public:   

             Tree(string name);                            

             virtual void View()=0;          

             int GetLevel()const;

             Tree *GetParent()const;

             void SetParent(Tree *_parent);

             string GetName()const;        

             virtual void AddChild(Tree *child);       

             virtual void RemoveChild(Tree *child);               

protected:

             int GetSize()const;

};

 

//Tree.cpp

#include "Tree.h"

 

Tree::Tree(string name):name(name)

{

             parent = 0;

}

 

int Tree::GetLevel()const

{

             int level = 0;

             Tree *ancestor = this->parent;

             while(ancestor)

             {

                           level++;

                           ancestor = ancestor->GetParent();

             }

             return level;

}

Tree *Tree::GetParent()const

{

             return parent;

}

void Tree::SetParent(Tree *_parent)

{

             parent = _parent;   

}

string Tree::GetName()const

{

             return name;

}

void Tree::AddChild(Tree *child)

{

            

}

 

void Tree::RemoveChild(Tree *child)

{           

}

int Tree::GetSize()const

{

             return name.size() + GetLevel()*2;

}

 

//Path.h

#pragma once

#include "Tree.h"

 

class Path :

             public Tree

{           

public:

             Path(string path);

             ~Path(void);         

             virtual void View();

};

 

//Path.cpp

#include "Path.h"

 

Path::Path(string path):Tree(path)

{

}

 

Path::~Path(void)

{

            

}

void Path::View()

{

             int size = GetSize();

             cout<<std::setiosflags(std::ios::right)<<std::setw(size);

             cout<<std::setfill(' ')<<GetName()<<endl;         

}

 

//Category.h

#pragma once

#include "Tree.h"

 

typedef vector<Tree *> Children;

typedef vector<Tree *>::iterator Iter;

 

class Category :

             public Tree

{

             Children children;  

public:

             Category(string name);

             ~Category(void);

             virtual void View();

             virtual void AddChild(Tree *child);       

             virtual void RemoveChild(Tree *child);               

};

 

//Category.cpp

#include "Category.h"

 

Category::Category(string name):Tree(name)

{

}

 

Category::~Category(void)

{           

             Iter seek = children.begin();

             Iter end = children.end();

 

             for( ; seek != end; ++seek)

             {

                           delete (*seek);

             }           

}

void Category::View()

{

             int size = GetSize();

             cout<<std::setiosflags(std::ios::right)<<std::setw(size);

             cout<<std::setfill(' ')<<GetName()<<"-C"<<endl;

            

             Iter seek = children.begin();

             Iter end = children.end();

             Tree *child = 0;

             for( ; seek != end; ++seek)

             {

                           child = (*seek);

                           child->View();

             }

}

 

void Category::AddChild(Tree *child)

{

             child->SetParent(this);

             children.insert(children.begin(),child);

}

 

void Category::RemoveChild(Tree *child)

{

             child->SetParent(0);

             Iter seek = std::find(children.begin(),children.end(),child);

             if(seek != children.end())

             {

                           children.erase(seek);

             }

}

 

//Demo.cpp

#include "common.h"

#include "Category.h"

#include "Path.h"

Tree *MakeDemoLocationTree();

Tree *MakeDemoDateTree();

int main()

{

             Tree *tree = new Category("사진 트리");

             tree->AddChild(MakeDemoLocationTree());

             tree->AddChild(MakeDemoDateTree());

             tree->View();

             delete tree;

             return 0;

}

 

Tree *MakeDemoLocationTree()

{

             Tree *tree = new Category("지역");

             Tree *sub1 = new Category("제주");

             Tree *sub2 = new Category("천안");    

             Tree *sub2_1 = new Path("C:\\사진\\현충사의 ");

             sub2->AddChild(sub2_1);

             Tree *sub3 = new Category("서울");

             Tree *sub4 = new Path("C:\\사진\\외도");

 

             tree->AddChild(sub1);

             tree->AddChild(sub2);

             tree->AddChild(sub3);

             tree->AddChild(sub4);

             return tree;

}

Tree *MakeDemoDateTree()

{

             Tree *tree = new Category("날짜");

             Tree *sub1 = new Category("20120429");         

             Tree *sub1_1 = new Path("C:\\사진\\외도");

             sub1->AddChild(sub1_1);

             Tree *sub2 = new Category("20120407");         

             Tree *sub2_1 = new Path("C:\\사진\\현충사의 ");

             sub2->AddChild(sub2_1);

             Tree *sub3 = new Category("20120507");

             Tree *sub3_1 = new Path("C:\\사진\\일산 고구마 모종");

             sub3->AddChild(sub3_1);

            

 

             tree->AddChild(sub1);

             tree->AddChild(sub2);

             tree->AddChild(sub3);

 

             return tree;

}


IT 전문가로 가는 길 Escort GoF의 디자인 패턴
국내도서
저자 : 장문석
출판 : 언제나휴일 2013.04.01
상세보기


 

반응형