-----------------------------------------------------------------------------
[Proxy]
의도:
다른 객체에 접근하기 위해 중간 대리 역활을 하는 객체를 둔다.
다른 이름:
Surrogate
-----------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////
//
// A Structural part of GoF's Design Patterns 
//
// - Proxy
//
/////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <memory>
#include <map>
#include <string>
#include <list>
#include <algorithm>
#define USE_HANDLE 1
#if (USE_HANDLE==1)
/////////////////////////////////////////////////////////////////////////////
// 
// Handle
//
/////////////////////////////////////////////////////////////////////////////
template<typename T>
class CRefCountedInstance
{
public:
 CRefCountedInstance ();
public:
 inline void AddRef       (void);
 inline void Release      (void);
 inline void Assign       (T *p);
 inline bool IsReferenced (void);
 inline T*   GetInstance  (void);
private:
 T   *Instance_;
 int  RefCount_;
};
template<typename T>
CRefCountedInstance<T>::CRefCountedInstance () : 
 RefCount_ (0),
 Instance_ (0)
{
}
template<typename T>
void CRefCountedInstance<T>::AddRef (void)
{
 RefCount_++;
}
template<typename T>
void CRefCountedInstance<T>::Release (void)
{
 if (RefCount_>0)
 {
  RefCount_--;
 }
 if (RefCount_==0)
 {
  if (Instance_)
  {
   delete Instance_;
  }
  Instance_ = 0;
 }
}
template<typename T>
void CRefCountedInstance<T>::Assign (T *p)
{
 Instance_ = p;
 AddRef ();
}
template<typename T>
bool CRefCountedInstance<T>::IsReferenced (void)
{
 if (RefCount_==0)
  return false;
 return true;
}
template<typename T>
T* CRefCountedInstance<T>::GetInstance (void)
{
 return Instance_;
}
template<typename T>
class Handle
{
public:
 Handle ();
 explicit Handle (T *p);
 Handle (const Handle<T> ©);
 virtual ~Handle ();
public:
 Handle<T>& operator = (const Handle<T>& rhs);
public:
 inline T& operator*  () const;
 inline T* operator-> () const;
 inline T* Get    (void) const;
private:
 CRefCountedInstance<T>* Rep_;
};
template<typename T>
Handle<T>::Handle () : Rep_(0)
{ 
}
template<typename T>
Handle<T>::Handle (T *p)
{
 Rep_ = new CRefCountedInstance<T>();
 Rep_->Assign(p);
}
template<typename T>
Handle<T>::Handle (const Handle<T> ©)
{
 Rep_ = copy.Rep_;
 if (Rep_)
  Rep_->AddRef ();
}
template<typename T>
Handle<T>::~Handle ()
{
 if (Rep_)
 {
  Rep_->Release ();
  if (!Rep_->IsReferenced())
   delete Rep_;
 }
}
template<typename T>
Handle<T>& Handle<T>::operator = (const Handle<T>& rhs)
{
 if (this == &rhs) return *this;
 if (Rep_)
  Rep_->Release ();
Rep_ = rhs.Rep_;
 if (Rep_)
  Rep_->AddRef ();
 return *this;
}
template<typename T>
T& Handle<T>::operator*() const 
{ 
 return *(Rep_->GetInstance()); 
}
template<typename T>
T* Handle<T>::operator -> () const
{
 if (Rep_==0)
  return 0;
 return (Rep_->GetInstance());
}
template<typename T>
T* Handle<T>::Get (void) const
{
 if (Rep_==0)
  return 0;
 return (Rep_->GetInstance());
}
#endif
/////////////////////////////////////////////////////////////////////////////
//
// Proxy
//
/////////////////////////////////////////////////////////////////////////////
class Subject
{
public:
 virtual ~Subject() {}
public:
 virtual void Request (void) = 0;
 virtual void SetData (int ) = 0;
};
class RealSubject : public Subject
{
public:
 explicit RealSubject (int n) :
  Data_ (n)
 {
  std::cout << "RealSubject::RealSubject(" << Data_ << ")" << std::endl;
 }
 virtual ~RealSubject ()
 {
  std::cout << "RealSubject::~RealSubject(" << Data_ << ")" << std::endl;
 }
public:
 virtual void Request (void)
 {
  std::cout << "RealSubject::Request(): Data_ = " << Data_ << std::endl;
 }
 virtual void SetData (int n)
 {
  Data_ = n;
 }
private:
 int Data_;
};
#if (USE_HANDLE==1)
class Proxy :
 public Subject
{
public:
 Proxy() : SubjectData_(0)
 {
 }
 explicit Proxy (int n) : 
  SubjectData_ (n)
 {
 }
 Proxy (const Proxy ©)
 {
  const_cast<Proxy&>(copy).Load();
  SubjectData_ = copy.SubjectData_;
  Subject_     = copy.Subject_;
 }
virtual ~Proxy () {}
public:
 virtual void Request (void)
 {
  GetSubject()->Request();
 }
 virtual void SetData (int n)
 {
  GetSubject()->SetData(n);
 }
private:
 Subject* GetSubject (void)
 {
  if (Subject_.Get()==0)
  {
   Handle<Subject> s ( new RealSubject(SubjectData_) );
   Subject_ = s;
  }
  return Subject_.Get();
 }
public:
 void Load (void)
 {
  GetSubject();
 }
public: 
 Proxy& operator = (const Proxy& rhs)
 {
  if (this == &rhs) return *this;
  const_cast<Proxy&>(rhs).Load();
  SubjectData_ = rhs.SubjectData_;
  Subject_     = rhs.Subject_;
  return *this;
 } 
private:
 Handle<Subject>  Subject_;
 int              SubjectData_;
};
#else
class Proxy :
 public Subject
{
public:
 Proxy() : 
  SubjectData_(0),  
  Subject_    (0)
 {
 }
 explicit Proxy (int n) : 
 SubjectData_ (n),
  Subject_     (0)
 {
 }
 virtual ~Proxy () 
 {
  if (Subject_)
   delete Subject_;
 }
public:
 virtual void Request (void)
 {
  GetSubject()->Request();
 }
 virtual void SetData (int n)
 {
  GetSubject()->SetData(n);
 }
private:
 Subject* GetSubject (void)
 {
  if (Subject_==0)
  {
   Subject_ = new RealSubject(SubjectData_);
  }
  return Subject_;
 }
private:
 Subject         *Subject_;
 int              SubjectData_;
};
#endif
/////////////////////////////////////////////////////////////////////////////
// 
// Startup
//
/////////////////////////////////////////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{ 
#if (USE_HANDLE==1)
 std::cout << "(USE_HANDLE==1)" << std::endl << std::endl;
 Proxy a(1);
 Proxy b;
 Proxy c;
 std::cout << "a.Load();" << std::endl;
 //a.Load();
 std::cout << std::endl;
 std::cout << "b=a;" << std::endl;
 b=a;
 std::cout << std::endl;
 std::cout << "a.Request ();" << std::endl;
 a.Request ();
 std::cout << std::endl;
 std::cout << "a.SetData (2);" << std::endl;
 a.SetData (2);
 std::cout << std::endl;
 std::cout << "b.Request ();" << std::endl;
 b.Request ();
 std::cout << std::endl;
 std::cout << "c=a" << std::endl;
 c=a;
 std::cout << "c.Request()" << std::endl;
 c.Request ();
 std::cout << std::endl;
#else
 std::cout << "(USE_HANDLE==0)" << std::endl << std::endl;
 Proxy       a(1);
 RealSubject b(2);
 std::cout << std::endl;
 std::cout << "a.Request()" << std::endl;
 a.Request (); // late creating instance
 std::cout << std::endl;
 std::cout << "a.Request()" << std::endl;
 b.Request ();
 std::cout << std::endl;
#endif
 return 0;
}
-----------------------------------------------------------------------------
(USE_HANDLE==1)
a.Load();
RealSubject::RealSubject(1)
b=a;
a.Request ();
RealSubject::Request(): Data_ = 1
a.SetData (2);
b.Request ();
RealSubject::Request(): Data_ = 2
c=a
c.Request()
RealSubject::Request(): Data_ = 2
RealSubject::~RealSubject(2)
-----------------------------------------------------------------------------
(USE_HANDLE==0)
RealSubject::RealSubject(2)
a.Request()
RealSubject::RealSubject(1)
RealSubject::Request(): Data_ = 1
a.Request()
RealSubject::Request(): Data_ = 2
RealSubject::~RealSubject(2)
RealSubject::~RealSubject(1)