C++面向对象编程原则及人类示例

时间:2021-07-30 17:23:00
================================================================================
标题: 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");

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



================================================================================