-----------------------------------------------------------------------------
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"

Posted by 셈말짓기 :