|
|
面向对象的优秀之处
本文提要
1 论述面向对象的好处和问题
2 网游的 client 和 server 的问题(他们做些什么?)
3 (在细节上)正确区分“面向对象思想”和“面向过程思想”
4 但是!从大框架上,一切都是应该用“面向对象思想”!
5 不过...作为一个整体来分析,本质上,程序都是面向过程的
6 “本文有自相矛盾的地方!?”----不,我没有!
引子
最近我采用的架构是,AI 和 核心逻辑分开。AI通过和人类玩家一样的接口与逻辑交互。
这对于网络游戏同样适用,每个client(人类玩家)都要和server的核心逻辑交互。
而client, AI 他们不能自己决定一些东西的数值,必须通过server的核心逻辑。
(上述各个模块间的交互,分为“直接读取”“消息通知”,而不允许直接进行非const函数调用)
以上是大框架。而在细节方面,近期我基本上只考虑了server的核心逻辑。
昨天有位朋友说了自己的见解:“游戏,就是一些能够自主行为的对象,加上制约这些对象的规律”
自主行为,比如说“我要吃饭”;规律,比如说“不吃饭不能生存”
此外,请大家注意思维上的“层次化”。如果把这世界看作一个整体,那么万物都要受到规律的制约;
然而进一步细化,则可以分为“意识世界”(能动的)和“外界世界”(受外界的自然规律制约)
下面进入正题。
开门见山,因为大家都知道 OO ,所以我先给出本人构思的一种
“纯粹面向对象模型”(稍后还会修改)
class CPureObjectABC : public IProcess //如果用win32多线程就不需要继承IProcess
{
private: // 私有成员
list<YourMsg> m_listMsgs;
Type m_aaa;
Type m_bbb;
public: // 共有成员
Type get_XXX()const; // 询问属性
void PostMessage( YourMsg msg ); // 通知消息
void DoSomething(); // 不推荐
public: // 从IProcess继承而来(不是必需的)
virtual void Update( UInt32 dt ); // 如果用win32多线程就不需要这个
};
这个模型的意图,我想很直接,就是定义了一个可以并行做事情的“对象”。对象之间可以随便取得属性,
但是,决不允许相互 直接 设置(Write) 属性,而只能通过 PostMessage() 进行通知,或者函数调用。
不过,我不推荐用函数调用,因为主调对象必须等待被调函数返回后才能继续工作,而程序员很容易忘记这一点。
楼主想通过这个,说明什么?
我看到一篇文章说,OO是为了解决“软件危机”而发明出来的。“对象”的概念,正如团队中的每个程序员,
大家可以相互交流,相互配合。(比如,“我看看别人在做什么,然后决定我自己该做什么”)
但我还看到一文章说,“C++, java不是纯粹的 OO, 还依赖于过程”。
是啊,正因为“不纯粹的 OO”的思想(我认为是思想),给我们引来过许多有趣的问题和故事,
所以,我想说的是,举一个纯粹的OO模型的例子。注意,只是例子!
(gc, refcount之类的东西因为“比较底层”所以不在我们的讨论范围之内。)
现在我们给出了一个“纯粹的OO”。那么,如何编写程序?好处在哪里?
----这和现实生活中人与人的协作,是一样的。你要运作一个团队,就必须相互合作。
换来的好处是,你可以进行“分工”,即每个人和别人配合,完成自己的工作。
历史上,OO将人们从“软件危机”中挽救了出来,正是因为OO,可以进行“分工”即“模块化”。
OO 的伟大思想,少不了“人”这个概念。没有“人”就没有 OO, 没有“人与人的合作”,OO就不能工作。
也就是说,编写OO程序,必须要尽可能考虑:别的对象可能会做什么?那么我应该如何应对?
----即,要拥有“与人合作”的 思 想 !而不应当鲁莽地做事,也不能 假 定 “别人肯定会听我的”
----虽然也可以直接调用public函数(不推荐),但是,不要认为,这个函数“一定会听我的话”。
问题的出现
上面说了,OO运用的是“人与人协作”的思想。换言之,就是“人治”。
这样无法解决某些问题,特别是在游戏中,比如,2个角色相互厮杀,他们的受伤计算。
在真实的人类社会中,如果“动真格的”那么“受不受伤”并不是2个人之间的相互合作,
而是由“自然规律”决定的!
于是,纯粹的OO,就给我们的编程,带来了一定的问题!我们来看一下如何解决:
(1) “不动真格的,这只是游戏”。
由于一切都是“人文主义”,所以,姑且把2个角色的PK,
当作是一场玩闹,不动真格的,2个角色“相互配合”即可。但这种设计模式,要求我们的程序员,
能够高度合作,稍有差池,游戏的规则,就不能够精确保证。
(2)“请一个裁判,或者老板”。
假设2个角色的PK,是一场“表演赛”。而他们,必须听命于“裁判”“老板”。
首先,作为员工,肯定要和老板合作,否则就回家去了。而PK双方,不必合作,他们直接听命于“老板”即可。
但这种设计模式,要求 1 员工必须要能和老板合作。 2 老板自己不能出错。
(3)使用C++, java等“不纯粹的OO”。
这种模式有时候是优秀的,有时候是糟糕的。比如说,“我砍你,我可以直接减少你的 HP。”
但也可以这样:你被发现我砍,你减少自己的 HP”。。。
根本原因在于(后面详解),“OO的概念不纯粹,和面向过程没有区分开”。
(4)不使用 OO !?
既然我们发现,上述(1)(2)解决起来不方便,上述(3)是好坏参半,那么,我们就不要 OO !
不要OO,就免去了OO的麻烦事,保证了一些游戏规则的精确化,绝对化。
我们继续往下分析。。。
在文章开头我说了“游戏,就是一些能够自主行为的对象,加上制约这些对象的规律”
所谓“自主行为的对象”,当然我们用 (纯粹的) OO 去实现即可。
而“制约这些对象的规律”,是 OO 之外的事情,我推荐,用面向过程最好不过了。
“规律如何制约对象?”
对象之间的交互,通过“get_XXX()const”还有“PostMessage”,这是人与人之间的“友好的”交互。
而,“自然规律”,是不会和你“讨价还价”的!说1就是1,说2就是2,由不得你!
换言之,“自然规律”,不会通过get_XXX询问你的属性值,也不可能 PostMessage 通知你。
更不可能调用你的一个函数,等你处理完返回。(俗话说“水火无情”就是这个道理)
那么,我们需要将对象的一部分数据成员,直接公开给“自然规律”。
而自然规律,使用面向对象编码,直接操作这些数据。
那么,我们修改一下对象的代码:
class CPureObjectABC_2 : public IProcess //如果用win32多线程就不需要继承IProcess
{
law: // 想象的关键字
Type m_bbb; // 直接受自然规律制约的成员变量
private: // 私有成员
list<YourMsg> m_listMsgs;
Type m_aaa;
public: // 共有成员
Type get_XXX()const; // 询问属性
void PostMessage( YourMsg msg ); // 通知消息
void DoSomething(); // 不推荐
public: // 从IProcess继承而来(不是必需的)
virtual void Update( UInt32 dt ); // 如果用win32多线程就不需要这个
};
我用了一个想象的“law”关键字。即受外界自然规律制约的变量。你可以自由实现。
“自然规律”怎么编码??
----用面向过程 思想 即可,具体方法,如果是游戏逻辑的话,可以参考我的“浅谈游戏逻辑”一文。
但上面的这种模式,还存在一个小问题就是,“受自然规律制约的成员变量”能够由我自己随便修改??
在应用软件开发中,这或许不算什么问题,因为软件本来就不是什么“真实的”东西。
而在游戏开发中,比如你受伤了,这是“规律”,你还能说改就改??......我们看看下面的这种模型。
class CPureObjectABC_Matter : public IProcess //如果用win32多线程就不需要继承IProcess
{
friend class CLaw; // 自然规律 - 虽然是“class”但完全是面向过程思想
private: // 想象的关键字
Type m_bbb; // 直接受自然规律制约的成员变量。
public:
Type get_BBB()const;
};
class CPureObjectABC_Mind : public IProcess //如果用win32多线程就不需要继承IProcess
{
private:
CPureObjectABC_Matter *matter;
private: // 私有成员
list<YourMsg> m_listMsgs;
Type m_aaa;
public: // 共有成员
Type get_XXX()const; // 询问属性
void PostMessage( YourMsg msg ); // 通知消息
void DoSomething(); // 不推荐
public: // 从IProcess继承而来(不是必需的)
virtual void Update( UInt32 dt ); // 如果用win32多线程就不需要这个
};
上面给出的只是基本原理,具体怎么编码因人而异,为了简单,我就不多废话了 
这种模型,很类似于我说的“AI 和逻辑分离”的架构。因为 AI 就是“mind”,客户端也是“mind”;
而server的核心逻辑,就是一个绝对的“物质世界”以及“规则”。
这种模型,也更像是,“PK”,作为人类或AI,可以有“自由意志”,
然后,能动地,去操纵“自己的身体”以及“武器”,但都要受到“规律”的制约。
(注意了阿!自己的身体,也属于外界物质世界,因为你不可能直接控制你的 每 个 细 胞 的 生 长 !)
还是那句话,“规律”具体编码,本文不讨论。
...那么,从大框架上来看,我们不妨这么认为:
“规律”也是一个有自由意志的“对象”。人要和规律“合作”,了解规律,克服困难。
换言之,拟人化地把“老天爷”当成一个“人”。
人啊,要在这世界上生存,就必须和大自然“合作”,不是吗?
不过话虽如此,以唯物论观点,将程序(client + server)作为一个整体来分析,
他们本质上都是“面向过程思想”。。。毕竟,CPU 不懂什么“面向对象”。。。
“发现楼主有严重的自相矛盾!?”
“楼主说,在 OO 模式下,(2)“请一个裁判,或者老板”解决起来不方便,就是说不要面向对象,
而后面又说,从大框架来看,<自然规律>也是一个`对象`,这不矛盾吗?”
不矛盾,在 OO 模式下,处理 相互 PK 问题,“定义一个老板对象”相对好一些,但还是不太方便。
你怎么确信,员工肯定和老板合作呢?
就好比,允许client拥有游戏逻辑,那么,如何和server正确合作?还有,不担心外挂问题吗?
虽然不是“点对点”游戏,想必来说好一些,这没错,但是,还是有一些问题的,不是吗?
----所以,最好让server处理所有游戏逻辑。
类似地,应该将“员工的肉体”转移到“老板”中去,即,“老板”进化为“上帝”。
既然员工不存在肉体,那么,“上帝老板”这个“对象”,就代表了“绝对的规则”,
而“上帝老板”的 内 部 呢(包含所有员工的肉体!而不仅仅是老板自己!),
采用“面向过程思想”来编写。
----这也就是我说的“某些情况下,不要用 OO,而要用面向过程”...游戏核心逻辑还是比较庞大的体系,
研究如何用面向过程去实现它,则是本外之外的广大话题了。。。
说不定,一个上帝忙不过来,内部要分几个上帝一起合作呢(但不能分太多!否则面向过程的“权威”何在?)
|
|