2017年12月23日 星期六

[轉貼]強制實作

此文截取自 http://www.programmer-club.com.tw/ShowSameTitleN/c/46861.html

用一個範例做個總結,也感謝 coco 提供的 assert,在 C++ 沒有提供 must 繼承實作之下,還能做到類似的效果,讓程式簡潔不少。但問題由原本的強制繼承實作,變成須強制 assert 實作,更不好達成,由此看出 must 繼承實作的須要性

範例主要展示 prototype pattern 及 visitor pattern 的架構,不過 visitor pattern 做了改良,可以
採用 ClassID 做配對,可以在執行時期做較機動的處理,但為了減少篇幅和難度,還是寫死未做較機動的
處理

Class C 是為了表現未強制實作的後果,有幾處做了 remark,把 remark 的地方恢復,就可正常執行


#include <map>
#include <memory>
#include <string>
#include <assert.h>   /* assert */
#include <typeinfo>   /* assert */
#include <iostream>
using namespace std;
// 插件的識別碼
#define Base_ClassID u8"14432A2FAECE4DA7A33CDA7472FB61DE"
#define A_ClassID u8"9EED77B5BD97404B85A390E2806FE435"
#define B_ClassID u8"11B5DCB493744F9B9A7C14343CF609A6"
#define C_ClassID u8"20DB108E78284B8390D258A4626523AC"
class Visitor;
class Base;
class Prototype
{
  virtual Prototype *Clone() const = 0;
public:
};

class Acceptor
{
  virtual string GetClassID() const = 0;
public:
  virtual void Accept(Visitor *v) = 0;
  friend class Visitor;
};
class Visitor
{
protected:
  string GetClassID(Acceptor *pAcceptor) const
  {
    return pAcceptor->GetClassID();
  }
  virtual void Visit(Acceptor *pAcceptor) = 0;
public:
  
  friend class Base;
};
class Base:public Prototype, public Acceptor
{
  virtual string GetClassID() const override
  {
    // 不准許 Base 被繼承卻沒有覆寫 GetClassID()
    assert(strcmp(typeid(Base).name(), typeid(*this).name()) == 0);
    return Base_ClassID;
  }
  virtual void Accept(Visitor *v) override final
  {
    v->Visit(this);
  }
public:
  virtual Base *Clone() const override
  {
    // 不准許 Base 沒有被繼承還執行 Clone()
    assert(strcmp(typeid(Base).name(), typeid(*this).name()) != 0);
    return new Base(*this);
  }
};
/***/
class CustomVisitor
{
public:
  virtual void Visit(Acceptor *pAcceptor) const = 0;
};
class VisitorManager :public Visitor
{
  map<string, shared_ptr<CustomVisitor> > m_CustomVisitorMap;
  virtual void Visit(Acceptor *pAcceptor) override
  {
    string ID = GetClassID(pAcceptor);
    shared_ptr<CustomVisitor> CustomVisitor_Ptr = m_CustomVisitorMap[ID];
    if (CustomVisitor_Ptr)
      CustomVisitor_Ptr->Visit(pAcceptor);
    else
      cout << "物件找不到相應的 CustomVisitor" << endl;
  }
public:
  VisitorManager();
};
class ObjPool
{
  map<string, shared_ptr<Base> > m_BaseMap;
public:
  ObjPool();
  Base *Get(string ClassID)
  {
    shared_ptr<Base> Src = m_BaseMap[ClassID];
    if (Src)
      return Src->Clone();
    else
      return nullptr;
  }
};
/***/
class BaseVisitor :public CustomVisitor
{
  virtual void Visit(Acceptor *pAcceptor) const override
  {
    Base *pBase = static_cast<Base*>(pAcceptor);
    cout << "Base 被 Clone,請檢查..." << endl;
  }
public:
};
class A :public Base
{
  string m_Name{ "class A" };
  virtual string GetClassID() const override
  {
    // 不准許 A 被繼承卻沒有覆寫 GetClassID()
    assert(strcmp(typeid(A).name(), typeid(*this).name()) == 0);
    return A_ClassID;
  }
  virtual A *Clone() const override
  {
    // 不准許 A 被繼承卻沒有覆寫 Clone()
    assert(strcmp(typeid(A).name(), typeid(*this).name()) == 0);
    return new A(*this);
  }
public:
  void SayHI()
  {
    cout << "HI! My name is " << m_Name << endl;
  }
};
class B :public Base
{
  string m_Name{ "class B" };
  virtual string GetClassID() const override
  {
    // 不准許 B 被繼承卻沒有覆寫 GetClassID()
    assert(strcmp(typeid(B).name(), typeid(*this).name()) == 0);
    return B_ClassID;
  }
  virtual B *Clone() const override
  {
    // 不准許 B 被繼承卻沒有覆寫 Clone()
    // assert(strcmp(typeid(B).name(), typeid(*this).name()) == 0);
    return new B(*this);
  }
public:
  void SayHello()
  {
    cout << "Hello! My name is " << m_Name << endl;
  }
};
class C :public B
{
  int Age{ 100 };
  virtual string GetClassID() const override
  {
    // 不准許 C 被繼承卻沒有覆寫 GetClassID()
    assert(strcmp(typeid(C).name(), typeid(*this).name()) == 0);
    return C_ClassID;
  }
  /*
  virtual C *Clone() const override
  {
    // 不准許 C 被繼承卻沒有覆寫 Clone()
    assert(strcmp(typeid(C).name(), typeid(*this).name()) == 0);
    return new C(*this);
  }
  */
public:
  void HowOld()
  {
    cout << "I am " << Age << " years old" << endl;
  }
};
class AVisitor :public CustomVisitor
{
  virtual void Visit(Acceptor *pAcceptor) const override
  {    
    // assert(strcmp(typeid(A).name(), typeid(*pAcceptor).name()) == 0);
    A *pA = static_cast<A*>(pAcceptor);
    pA->SayHI();
    cout << "A 複製成功..." << endl;
  }
public:
};
class BVisitor :public CustomVisitor
{
  virtual void Visit(Acceptor *pAcceptor) const override
  {
    // assert(strcmp(typeid(B).name(), typeid(*pAcceptor).name()) == 0);
    B *pB = static_cast<B*>(pAcceptor);
    pB->SayHello();
    cout << "B 複製成功..." << endl;
  }
public:
};
class CVisitor :public CustomVisitor
{
  virtual void Visit(Acceptor *pAcceptor) const override
  {
    // assert(strcmp(typeid(C).name(), typeid(*pAcceptor).name()) == 0);
    C *pC = static_cast<C*>(pAcceptor);
    pC->SayHello();
    pC->HowOld();
    cout << "C 複製成功..." << endl;
  }
public:
};
ObjPool::ObjPool()
{
  // 註冊所有 Base 的 Derived
  m_BaseMap[string(Base_ClassID)] = shared_ptr<Base >(new Base);
  m_BaseMap[string(A_ClassID)] = shared_ptr<Base >(new A);
  m_BaseMap[string(B_ClassID)] = shared_ptr<Base >(new B);
  m_BaseMap[string(C_ClassID)] = shared_ptr<Base >(new C);
}
VisitorManager::VisitorManager()
{
  // 註冊所有 CustomVisitor 的 Derived
  m_CustomVisitorMap[string(Base_ClassID)] = shared_ptr<CustomVisitor >(new BaseVisitor);  
  m_CustomVisitorMap[string(A_ClassID)] = shared_ptr<CustomVisitor >(new AVisitor);
  m_CustomVisitorMap[string(B_ClassID)] = shared_ptr<CustomVisitor >(new BVisitor);
  m_CustomVisitorMap[string(C_ClassID)] = shared_ptr<CustomVisitor >(new CVisitor);
}
int main()
{
  ObjPool MyObjPool;
  VisitorManager MyVisitorManager;  
  shared_ptr<Base> Obj_Ptr(MyObjPool.Get(string(A_ClassID)));
  shared_ptr<Acceptor> Acceptor_Ptr = static_pointer_cast<Acceptor>(Obj_Ptr);
  Acceptor_Ptr->Accept(&MyVisitorManager);
  cout << endl;
  Obj_Ptr = shared_ptr<Base>( MyObjPool.Get(string( C_ClassID )) );
  Acceptor_Ptr = static_pointer_cast<Acceptor>(Obj_Ptr);
  Acceptor_Ptr->Accept(&MyVisitorManager);  
  return 0;
}





沒有留言:

張貼留言