C++面向對象編程原則及人類示例

================================================================================
標題: C++面向對象編程原則及人類示例
作者: 葉飛虎
日期: 2017.10.12
--------------------------------------------------------------------------------

1. 概述
   在 C++ 面向對象編程中,有很多開發人員無法把控類,以及應該如何編寫。在編寫類時
有幾個原則必須遵循,這樣可以使類擁有健壯性及可用性。人類示例 TPerson 描述了類的
生命力,以及類的屬性、行爲和事件。

   面向對象編程的二個基本特徵:封裝和繼承。
   封裝的目的是爲了信息隱藏,並保證類數據成員的私有性和一致性,同時數據成員之間
是強耦合,而類與類之間應該弱耦合。

   繼承的目的是爲了擴充類的多樣性,多繼承和多態都是繼承的擴展方式,而繼承會增加
類與類之間的耦合性。


2. 面向對象編程的遵循原則
   a. 類的數據成員儘量放在 private 中,若要開放信息可以通過 public 屬性方法操作。
   b. 類屬性方法分爲: 讀取屬性和設置屬性,讀取屬性方法名直接用屬性名無需添加前綴,
      而設置屬性方法前面必須添加前綴 "Set" 並後跟屬性名。
   c. 類提供的 public 方法必須具有完備性,如:"Add" 則有 "Delete","Begin" 則有
      "End","Open" 則有 "Close","Start" 則有 "Stop" 等等。
   d. 類的 public 方法必須具有防禦能力,保證類成員數據安全,類就像一個封閉的城池,
      public 方法就像城門,爲了保證城池安全必須在城門有檢查,只有這樣才能使城池
      內事物免受破壞。
   e. 類少用繼承而多用聚合,通過聚合的方式封裝在新的類中,讓聚合的成員之間通過行
      爲和事件進行關聯,並形成成員間的強耦合。若要繼承最好使用單類繼承,而且單類
      繼承也能夠解決多類繼承問題,即通過聚合新類並繼承即可。
   f. 若類內部存在主動向外發起動作時,應該設置事件,並通過事件方式來解決未來問題。
      對象事件就是一個開放的接口,能夠綁定相同類型參數和返回值的對象方法,因爲無
      需知道方法所屬類就可以調用對象方法,具體使用可參見 TPerson 類。


3. 示例代碼, 請參見 "Person.cpp"
// =======================================
// Unit   : 面向對象編程的人類示例
// Version: 1.0.0.0 (build 2017.10.12)
// Author : 葉飛虎
// Email  : kyee_ye(at)126.com
// Copyright (C) Kyee workroom
// =======================================

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/* TPerson - 人類 */

class TPerson
{
public:
   // 人的存在狀態
   enum TState   {psNothing,           // 虛無
                  psEnding,            // 正在消亡
                  psComing,            // 正在孕育
                  psLiving};           // 活着

   // 性別
   enum TSex     {sexUnknown,          // 未知
                  sexFemale,           // 女性
                  sexMale,             // 男性
                  sexNeuter,           // 中性
                  sexF2Male,           // 女變性男
                  sexM2Female};        // 男變性女

   // 其他類別
   // ??? ... ...

public:
   // OnSound 事件
   typedef void (TObject::*TDoSound)(void* Sender, const TAudio& ASound);
   typedef struct
   {
      TDoSound    Method;
      void*       Object;
   } TOnSound;

   // OnView 事件
   typedef void (TObject::*TDoView)(void* Sender, const TAction& AView);
   typedef struct
   {
      TDoView     Method;
      void*       Object;
   } TOnView;

   // 其他事件
   // ??? ... ...

public:
   TPerson();
   virtual ~TPerson();

   // 屬性
   TState         State() const        { return FState; }
   bool           Living() const       { return FState == psLiving; }
   TDateTime      Birthday() const     { return FBirthday; }
   TDateTime      Deathday() const     { return FDeathday; }

   THeadInfo      HeadInfo();                            // 如: 頭髮、五官信息等等
   TBodyInfo      BodyInfo();                            // 如: 三圍信息等等
   TLimbInfo      LimbInfo();                            // 如: 上、下肢信息等等
   // ??? ... ...

   bool           CanProcreate() const                   // 是否能生育只是從性別上判斷
                  { return (FSex == sexFemale) || (FSex == sexMale); }
   TSex           Sex() const          { return FSex; }  // 性別
   KYString       Name() const         { return FSocialInfo.Name(); }
   KYString       CertID() const       { return FSocialInfo.CertID(); }
   TSocialInfo&   SocialInfo()         { return FSocialInfo; }
   // ??? ... ...

   TPerson*       Father() const       { return FFather; }
   TPerson*       Mother() const       { return FMother; }

   long           MateCount() const    { return FMates.Count(); }
   TPerson*       Mate(long AIndex) const
                  { return (TPerson*)FMates[AIndex]; }

   long           ChildCount() const   { return FChildren.Count(); }
   TPerson*       Child(long AIndex) const
                  { return (TPerson*)FChildren[AIndex]; }

   // 設置屬性
   bool           SetName(const KYString& AName)         // 設置姓名
                  { return FSocialInfo.SetName(AName); }
   bool           SetCertID(const KYString& ACertID)     // 設置身份標識
                  { return FSocialInfo.SetCertID(ACertID); }
   // ??? ... ...

   // 設置事件
   bool           SetOnSound(void* AObject, TDoSound ADoSound);
   bool           SetOnView(void* AObject, TDoView ADoView);
   // ??? ... ...

   // 生命的開始/結束
   bool           Begin(TPerson* AFather, TPerson* AMother);
   void           End(bool ANeedWait);

   // 呼吸/喝/喫
   void           Breathe(const TGas& AGas);
   void           Drink(const TLiquid& ALiquid);
   void           Eat(const TSolid& ASolid);
   // ??? ... ...

   // 聽到聲音/看到景象/軀體感受外部信息..
   void           Listen(void* Sender, const TAudio& ASound);
   void           See(void* Sender, const TAction& AView);
   // ??? ... ...

   // 結婚/生子
   void           Marry(TPerson* AMate);
   TPerson*       MakeChild(TPerson* AMate);

   // 其他方法
   // ??? ... ...

protected:
   // 狀態鎖
   void           Lock() const         { FLock.Enter(); }
   void           Unlock() const       { FLock.Leave(); }

   // 狀態引用計數增/減 1
   bool           IncRefCount();
   void           DecRefCount()        { InterlockedDecrement(&FRefCount); }

   // 對象次數增/減 1
   long           IncObjTimes()        { return InterlockedIncrement(&FObjTimes); }
   long           DecObjTimes()        { return InterlockedDecrement(&FObjTimes); }

   // 發出聲音/產生外觀活動/產生性別
   void           DoSound(const TAudio& ASound);
   void           DoView(const TAction& AView);
   void           DoSex(TSex ASex);
   // ??? ... ...

private:
   // 執行初始化/釋放相關對象
   bool           DoInitObjs();
   void           DoFreeObjs();

   // 執行開始/結束
   bool           DoBegin(TPerson* AFather, TPerson* AMother);
   void           DoEnd();

   // ??? ... ...

private:
   TKYCritSect    FLock;               // 狀態鎖
   TState         FState;              // 當前狀態
   long           FRefCount;           // 狀態引用計數
   long           FObjTimes;           // 對象引用次數
   TDateTime      FBirthday;           // 對象出生時間
   TDateTime      FDeathday;           // 對象消亡時間

   // 對象的內在實體對象: 內在對象之間強耦合, 並通過血管和神經元關聯, 而 DNA 直
   //                     接控制實體對象的變化, 產生物種的相似性和多樣性。
   // 注: 當對象消亡時, 其內在實體對象也隨之消亡
   TDNA*          FDNA;                // DNA 對象
   THead*         FHead;               // 頭對象
   TBody*         FBody;               // 軀體對象
   TLimb*         FLimb;               // 肢體對象
   // ??? ... ...

   // 對象社會特徵
   TSex           FSex;                // 性別
   TSocialInfo    FSocialInfo;         // 如: 身份證號、姓名、籍貫等等
   // ??? ... ...

   // 對象關係
   TPerson*       FFather;             // 父親
   TPerson*       FMother;             // 母親

   TKYList        FMates;              // 配偶列表
   TKYList        FChildren;           // 孩子列表

   // 事件
   TOnSound       FOnSound;            // 發出聲音事件, 如: 說話、鼓掌等等
   TOnView        FOnView;             // 行爲展示事件, 如: 跳舞等等
   // ??? ... ...

public:
   // 對象引用計數增/減 1(注: APerson 對象必須存在)
   static long    _IncRefPerson(TPerson* APerson)
                  { return APerson->IncObjTimes(); }
   static void    _DecRefPerson(TPerson* APerson)
                  { if (APerson->DecObjTimes() == 0) delete APerson; }
};

// ---------------- 構造函數和析構函數 ----------------
// 構造函數
TPerson::TPerson() : FMates(true), FChildren(true)
{
   // 初始化
   FState         = psNothing;
   FRefCount      = 0;
   FObjTimes      = 1;
   FBirthday      = 0;
   FDeathday      = 0;

   FDNA           = NULL;
   FHead          = NULL;
   FBody          = NULL;
   FLimb          = NULL;
   // ??? ... ...

   FSex           = sexUnknown;
   // ??? ... ...

   FFather        = NULL;
   FMother        = NULL;

   FOnSound.Method= NULL;
   FOnSound.Object= NULL;
   FOnView.Method = NULL;
   FOnView.Object = NULL;

   // 創建對象
   // ??? ... ...
}

// 析構函數
TPerson::~TPerson()
{
   // 生命結束
   End(true);

   // 釋放對象
   // ??? ... ...
}

// ---------------- 私有函數 ----------------
// 執行初始化相關對象
bool TPerson::DoInitObjs()
{
   // 初始化
   bool result = false;

   // 創建 DNA 對象
   FDNA  = new TDNA(this);
   if (FDNA != NULL)
   {
      // 創建對象列表
      FHead = new THead(this, FDNA);
      FBody = new TBody(this, FDNA);
      FLimb = new TLimb(this, FDNA);

      // 判斷是否創建成功
      if ((FHead != NULL) && (FBody != NULL) && (FLimb != NULL))
      {
         // 連接各個對象之間的血管及神經元, 神經中樞在頭部對象中
         // ??? ... ...

         // 設置 FHead 對象事件
         FHead->SetOnSound(&TPerson::DoSound);
         FHead->SetOnView(&TPerson::DoView);
         // ??? ... ...

         // 設置 FBody 對象事件
         FBody->SetOnSound(&TPerson::DoSound);
         FBody->SetOnView(&TPerson::DoView);
         FBody->SetOnSex(&TPerson::DoSex);
         // ??? ... ...

         // 設置 FLimb 對象事件
         FLimb->SetOnSound(&TPerson::DoSound);
         FLimb->SetOnView(&TPerson::DoView);
         // ??? ... ...

         // 成功
         result = true;
      }
      else
      {
         FreeAndNil(FHead);
         FreeAndNil(FBody);
         FreeAndNil(FLimb);
         FreeAndNil(FDNA);
      }
   }

   // 返回結果
   return result;
}

// 執行釋放相關對象
void TPerson::DoFreeObjs()
{
   FreeAndNil(FHead);
   FreeAndNil(FBody);
   FreeAndNil(FLimb);
   FreeAndNil(FDNA);
}

// 執行開始
bool TPerson::DoBegin(TPerson* AFather, TPerson* AMother)
{
   // 初始化
   bool result = false;

   // 生命只有一次
   if ((FMother == NULL) && (AFather != NULL) && (AMother != NULL)
                         && (AFather != this) && (AFather != AMother)
                         && (AMother != this) && AFather->IncRefCount())
   {
      if (AMother->IncRefCount())
      {
         // 能否可以生育
         if (AFather->CanProcreate() && AMother->CanProcreate()
                                     && (AFather->FSex == sexMale)
                                     && (AMother->FSex == sexFemale)
                                     && DoInitObjs())
         {
            // 父母對象
            FFather = AFather;
            FMother = AMother;

            // DNA 繼承自父母, 並孕育生命
            if (FDNA->Inherit(FFather->FDNA, FMother->FDNA) && DoGestate())
            {
               FBirthday = Now();
               result    = true;
            }
            else
               DoFreeObjs();
         }

         // 引用計數減 1
         AMother->DecRefCount();
      }

      // 引用計數減 1
      AFather->DecRefCount();
   }

   // 返回結果
   return result;
}

// 執行結束
void TPerson::DoEnd()
{
   // 通知內在實體對象衰竭
   FHead->Crash();
   FBody->Crash();
   FLimb->Crash();
   // ??? ... ...

   // 等待引用計數爲 0
   while (FRefCount > 0)
      Sleep(8);

   // 消亡時間
   FDeathday = Now();

   // 內在實體對象結束
   FHead->End();
   FBody->End();
   FLimb->End();
   FDNA->End();
   // ??? ... ...

   // 執行釋放相關對象
   DoFreeObjs();
}

// ---------------- 保護函數 ----------------
// 引用計數加 1
bool TPerson::IncRefCount()
{
   // 初始化
   bool result = false;

   // 引用計數加 1
   InterlockedIncrement(&FRefCount);
   if (FState == psLiving)
      result = true;
   else
      InterlockedDecrement(&FRefCount);

   // 返回結果
   return result;
}

// 發出聲音
void TPerson::DoSound(const TAudio& ASound)
{
   // 初始化
   TOnSound OnSound;
   OnSound.Method = NULL;

   // 取事件
   Lock();
   if (FState == psLiving)
      OnSound = FOnSound;
   Unlock();

   // 激發 OnSound 事件
   if (OnSound.Method != NULL)
      ((TObject*)OnSound.Object->*OnSound.Method)(this, ASound);
}

// 產生外觀活動
void TPerson::DoView(const TAction& AView)
{
   // 初始化
   TOnView OnView;
   OnView.Method = NULL;

   // 取事件
   Lock();
   if (FState == psLiving)
      OnView = FOnView;
   Unlock();

   // 激發 OnView 事件
   if (OnView.Method != NULL)
      ((TObject*)OnView.Object->*OnView.Method)(this, AView);
}

// 產生性別
void TPerson::DoSex(TSex ASex)
{
   FSex = ASex;
}

// ---------------- 公有函數 ----------------
// 如: 頭髮、五官信息等等
THeadInfo TPerson::HeadInfo()
{
   // 初始化
   THeadInfo result;

   // 引用計數加 1
   if (IncRefCount())
   {
      // 取頭部信息
      result = FHead->Info();

      // 引用計數減 1
      DecRefCount();
   }

   // 返回結果
   return result;
}

// 如: 三圍信息等等
TBodyInfo TPerson::BodyInfo()
{
   // 初始化
   TBodyInfo result;

   // 引用計數加 1
   if (IncRefCount())
   {
      // 取軀體信息
      result = FBody->Info();

      // 引用計數減 1
      DecRefCount();
   }

   // 返回結果
   return result;
}

// 如: 上、下肢信息等等
TLimbInfo TPerson::LimbInfo()
{
   // 初始化
   TLimbInfo result;

   // 引用計數加 1
   if (IncRefCount())
   {
      // 取肢體信息
      result = FLimb->Info();

      // 引用計數減 1
      DecRefCount();
   }

   // 返回結果
   return result;
}

// 設置 OnSound 事件
bool TPerson::SetOnSound(void* AObject, TDoSound ADoSound)
{
   // 初始化
   bool result = false;

   // 判斷狀態
   Lock();
   if (FState == psLiving)
   {
      FOnSound.Object = AObject;
      FOnSound.Method = ADoSound;
      result          = true;
   }
   Unlock();

   // 返回結果
   return result;
}

// 設置 OnView 事件
bool TPerson::SetOnView(void* AObject, TDoView ADoView)
{
   // 初始化
   bool result = false;

   // 判斷狀態
   Lock();
   if (FState == psLiving)
   {
      FOnView.Object = AObject;
      FOnView.Method = ADoView;
      result         = true;
   }
   Unlock();

   // 返回結果
   return result;
}

// 生命的開始
bool TPerson::Begin(TPerson* AFather, TPerson* AMother)
{
   // 初始化
   bool result   = false;
   bool boolNext = false;

   // 更改狀態
   Lock();
   if (FState == psNothing)
   {
      boolNext = true;
      FState   = psComing;
   }
   Unlock();

   // 判斷是否繼續
   if (boolNext)
   {
      // 執行開始
      result   = DoBegin(AFather, AMother);
      boolNext = false;

      // 更改狀態
      Lock();
      if (FState != psComing)
         boolNext = true;
      else if (result)
         FState   = psLiving;
      else
         FState   = psNothing;
      Unlock();

      // 判斷是否需要結束
      if (boolNext)
      {
         // 執行結束
         if (result)
         {
            DoEnd();
            result = false;
         }

         // 更改狀態(不需要加鎖)
         FState = psNothing;
      }
   }

   // 返回結果
   return result;
}

// 生命的結束
void TPerson::End(bool ANeedWait)
{
   // 初始化
   bool boolNext = false;
   bool boolWait = false;

   // 更改狀態
   Lock();
   if (FState == psLiving)
   {
      FState   = psEnding;
      boolNext = true;
   }
   else if (FState == psComing)
   {
      FState   = psEnding;
      boolWait = true;
   }
   else if (FState == psEnding)
      boolWait = ANeedWait;
   Unlock();

   // 判斷是否繼續
   if (boolNext)
   {
      // 執行結束
      DoEnd();

      // 更改狀態(不需要加鎖)
      FState = psNothing;
   }
   else if (boolWait)   // 等待 End 結束
      while (FState == psEnding)
         Sleep(8);
}

// 呼吸
void TPerson::Breathe(const TGas& AGas)
{
   // 引用計數加 1
   if (IncRefCount())
   {
      // 氣體進入身體
      // ??? ... ...

      // 引用計數減 1
      DecRefCount();
   }
}

// 喝
void TPerson::Drink(const TLiquid& ALiquid)
{
   // 引用計數加 1
   if (IncRefCount())
   {
      // 液體進入身體
      // ??? ... ...

      // 引用計數減 1
      DecRefCount();
   }
}

// 喫
void TPerson::Eat(const TSolid& ASolid)
{
   // 引用計數加 1
   if (IncRefCount())
   {
      // 固體進入身體
      // ??? ... ...

      // 引用計數減 1
      DecRefCount();
   }
}

// 聽到聲音
void TPerson::Listen(void* Sender, const TAudio& ASound)
{
   // 引用計數加 1
   if (IncRefCount())
   {
      // 大腦去分析聲音
      FHead->AnalyzeSound(Sender, ASound);

      // 引用計數減 1
      DecRefCount();
   }
}

// 看到景象
void TPerson::See(void* Sender, const TAction& AView)
{
   // 引用計數加 1
   if (IncRefCount())
   {
      // 大腦去分析景象
      FHead->AnalyzeView(Sender, AView);

      // 引用計數減 1
      DecRefCount();
   }
}

// 結婚
void TPerson::Marry(TPerson* AMate)
{
   // 引用計數加 1
   if ((AMate != NULL) && (AMate != this) && AMate->IncRefCount())
   {
      // 引用計數加 1
      if (IncRefCount())
      {
         // 加入列表
         FMates.Add(AMate);
         AMate->FMates.Add(this);

         // 引用計數減 1
         DecRefCount();
      }

      // 引用計數減 1
      AMate->DecRefCount();
   }
}

// 生子
TPerson* TPerson::MakeChild(TPerson* AMate)
{
   // 初始化
   TPerson* result = NULL;

   // 引用計數加 1
   if ((AMate != NULL) && (AMate != this) && AMate->IncRefCount())
   {
      // 引用計數加 1
      if (AMate->CanProcreate() && IncRefCount())
      {
         // 判斷能否生育能力
         if (CanProcreate() && (FSex != AMate->FSex))
         {
            // 創建對象
            TPerson* objChild = new TPerson;
            if (objChild != NULL)
            {
               // 父母對象
               TPerson* objFather = this;
               TPerson* objMother = AMate;
               if (FSex != sexMale)
               {
                  objFather = AMate;
                  objMother = this;
               }

               // 判斷生命是否孕育成功
               if (objChild->Begin(objFather, objMother))
               {
                  FChildren.Add(objChild);
                  AMate->FChildren.Add(objChild);
                  result = objChild;
               }
               else
                  delete objChild;
            }
         }

         // 引用計數減 1
         DecRefCount();
      }

      // 引用計數減 1
      AMate->DecRefCount();
   }

   // 返回結果
   return result;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/* 人類之間交互示例 */

// A 和 B 對象
TPerson A, B;

{
   // A 和 B 二個交談, 設置兩者交互事件
   A.SetOnSound(&B, (TPerson::TDoSound)&TPerson::Listen);
   A.SetOnView(&B,  (TPerson::TDoView)&TPerson::See);

   B.SetOnSound(&A, (TPerson::TDoSound)&TPerson::Listen);
   B.SetOnView(&A,  (TPerson::TDoView)&TPerson::See);

   // A 和 B 結婚
   A.Marry(&B);

   // A 和 B 生子, 並取名
   TPerson* objChild = A.MakeChild(&B);
   if (objChild != NULL)
      objChild->SetName("A-B-child1");

   // ??? ... ...
}



================================================================================
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章