-----------------------------------------------------------------------------
Compoiste 객체를 Visitor가 순회할때 자식 객체들은 Accept를 재귀호출하고 자신은 Visit를
수행하는 방법으로 순회 한다.
--------------------------------------------------------------------------------
#include <windows.h>
#include <tchar.h>
#include <list>
#include <string>
#include <algorithm>
#include <iostream>
#include <deque>
/////////////////////////////////////////////////////////////////////////////
//
// Base Patterns
//
//
/////////////////////////////////////////////////////////////////////////////
//// ------------------------------------------------------------------------
//// Visitor Pattern
//// ------------------------------------------------------------------------
class Visitable;
class Visitor
{
protected:
Visitor() {}
public:
virtual void Visit (Visitable *) {}
};
class Visitable
{
protected:
Visitable() {}
public:
virtual void Accept (Visitor &v)
{
v.Visit (this);
}
};
class VisitableObjectAcceptor
{
protected:
Visitor &Visitor_;
public:
explicit VisitableObjectAcceptor (Visitor &v) : Visitor_(v)
{
}
public:
void operator () (Visitable* o)
{
if (o)
{
o->Accept (Visitor_);
}
}
};
//// ------------------------------------------------------------------------
//// Composite Pattern
//// ------------------------------------------------------------------------
class Composite;
class Component : public Visitable
{
public:
virtual Composite* GetComposite (void)
{
return 0;
}
virtual void Add (Component* c) {};
virtual void Remove(Component* c) {};
};
class Composite : public Component
{
protected:
Composite () {}
public:
virtual Composite* GetComposite (void)
{
return this;
}
public:
virtual void Add (Component* c)
{
components_.push_back (c);
};
virtual void Remove(Component* c)
{
components_.remove (c);
};
virtual void Accept (Visitor &v)
{
v.Visit (this);
std::for_each(components_.begin(), components_.end(), VisitableObjectAcceptor(v));
}
protected:
std::list <Component*> components_;
};
class Leaf : public Component
{
};
/////////////////////////////////////////////////////////////////////////////
//
// Application
//
//
/////////////////////////////////////////////////////////////////////////////
//// ------------------------------------------------------------------------
//// Composite
//// ------------------------------------------------------------------------
class Directory : public Composite
{
public:
Directory (const std::string name) : name_ (name)
{
}
public:
virtual std::string GetName (void) const { return name_; }
virtual size_t GetFileCount (void) const { return components_.size(); }
protected:
std::string name_;
};
class File : public Leaf
{
public:
File (const std::string name, int size=0) : name_ (name), size_(size)
{
}
public:
virtual int GetSize (void) const { return size_; }
virtual std::string GetName (void) const { return name_; }
protected:
std::string name_;
int size_;
};
class Mp3File : public File
{
public:
Mp3File (const std::string filename) : File (filename, 1000) {}
};
class TxtFile : public File
{
public:
TxtFile (const std::string filename) : File (filename, 10) {}
};
//// ------------------------------------------------------------------------
//// Vistor
//// ------------------------------------------------------------------------
class Enumerator: public Visitor
{
public:
Enumerator ()
{
}
public:
virtual void Visit (Visitable *o)
{
File *file=dynamic_cast<File*> (o);
Directory *dir =dynamic_cast<Directory*> (o);
if (file) std::cout << "\"" << file->GetName() << "\"" << std::endl;
if (dir ) std::cout << "[" << dir ->GetName() << "]" << std::endl;
}
};
class CalcTotalSize : public Visitor
{
public:
CalcTotalSize () : m_TotalSize(0)
{
}
public:
virtual void Visit (Visitable *o)
{
File *file=dynamic_cast<File*> (o);
if (file)
{
m_TotalSize+=file->GetSize();
}
}
public:
int GetTotalSize (void) { return m_TotalSize; }
private:
int m_TotalSize;
};
/////////////////////////////////////////////////////////////////////////////
//
// Start up
//
//
/////////////////////////////////////////////////////////////////////////////
int _tmain (int argc, _TCHAR* argv[])
{
Directory dir_root ("RootDirectory");
Directory dir_sub1 ("SubDirectory1");
Directory dir_sub2 ("SubDirectory2");
Mp3File file_mp3_1 ("a.mp3");
Mp3File file_mp3_2 ("b.mp3");
TxtFile file_txt_1 ("a.txt");
TxtFile file_txt_2 ("b.txt");
dir_sub1.Add (&file_mp3_1);
dir_sub1.Add (&file_mp3_2);
dir_sub2.Add (&file_mp3_1);
dir_sub2.Add (&file_txt_1);
dir_root.Add (&dir_sub1);
dir_root.Add (&dir_sub2);
dir_root.Add (&file_txt_1);
dir_root.Add (&file_txt_2);
CalcTotalSize calc_size;
dir_root.Accept (calc_size);
std::cout << "# CalcTotalSize::GetTotalSize()=" << calc_size.GetTotalSize() << std::endl;
std::cout << std::endl;
std::cout << "# Enumerator" << std::endl;
Enumerator show_enum;
dir_root.Accept (show_enum);
return 0;
}
--------------------------------------------------------------------------------
# CalcTotalSize::GetTotalSize()=3030
# Enumerator
[RootDirectory]
[SubDirectory1]
"a.mp3"
"b.mp3"
[SubDirectory2]
"a.mp3"
"a.txt"
"a.txt"
"b.txt"