腾讯大讲堂05 面向对象应对之道

88
面面面面面面 面面面面面面 课课课课 课课课课 :penghao :penghao 2008-04-01 2008-04-01

Upload: areyouok

Post on 31-May-2015

3.311 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: 腾讯大讲堂05 面向对象应对之道

面向对象开发面向对象开发

课程开发课程开发 :penghao:penghao

2008-04-012008-04-01

Page 2: 腾讯大讲堂05 面向对象应对之道

课程目的课程目的 描述面向对象编描述面向对象编

程的一般性的手程的一般性的手法,原则 和技法,原则 和技巧巧

工欲善其事工欲善其事 ,, 必必先利其器。先利其器。

Page 3: 腾讯大讲堂05 面向对象应对之道

课程大纲课程大纲 引言引言 面向对象的面向对象的表达方法表达方法 面向对象的面向对象的五个原则五个原则 面向对象的面向对象的几个设计模式几个设计模式

Page 4: 腾讯大讲堂05 面向对象应对之道

我们面对的是什么?我们面对的是什么?

Page 5: 腾讯大讲堂05 面向对象应对之道

这种情况下的应对之道这种情况下的应对之道 规模大且服务不断的情况下对应的非功能规模大且服务不断的情况下对应的非功能

性需求就会要求比较多性需求就会要求比较多 . . 变化多且持续变化的情况下要求程序具有变化多且持续变化的情况下要求程序具有

良好的结构。本文档所关注的核心。良好的结构。本文档所关注的核心。

Page 6: 腾讯大讲堂05 面向对象应对之道

程序,服务具有良好结构有两个层程序,服务具有良好结构有两个层面的考虑面的考虑

大粒度的结构设计。关注的层面比较宏观。大粒度的结构设计。关注的层面比较宏观。这一块的知识参考 《面向模式的体系结这一块的知识参考 《面向模式的体系结构》 卷一。本文档不关注。构》 卷一。本文档不关注。

Page 7: 腾讯大讲堂05 面向对象应对之道

细粒度结构设计细粒度结构设计 -- 本文档关注的核心本文档关注的核心

Page 8: 腾讯大讲堂05 面向对象应对之道

什么代码写得好?什么叫坏的代码?什么代码写得好?什么叫坏的代码?有标准吗?有标准吗?

2-52-5

Page 9: 腾讯大讲堂05 面向对象应对之道
Page 10: 腾讯大讲堂05 面向对象应对之道

坏代码举例坏代码举例 僵化:很难对系统进行改动,因为每个改动都会僵化:很难对系统进行改动,因为每个改动都会

迫使许多对系统其他部分的改动。迫使许多对系统其他部分的改动。 脆弱:对系统的改动会导致系统综合改动的地方脆弱:对系统的改动会导致系统综合改动的地方

在概念上无关的许多地方出现问题。在概念上无关的许多地方出现问题。 牢固:很难解开系统的纠结,使之成为一些可重牢固:很难解开系统的纠结,使之成为一些可重

用的组件。用的组件。 粘滞:做正确的事情比做错误的事情要困难。粘滞:做正确的事情比做错误的事情要困难。 不必要的复杂:设计中包含不具有任何直接好处不必要的复杂:设计中包含不具有任何直接好处

的基础结构。的基础结构。 不必要的重复:不必要的重复: 晦涩:很难阅读,理解。晦涩:很难阅读,理解。 (引用于《敏捷软件开发:原则,模式与实践》 (引用于《敏捷软件开发:原则,模式与实践》

强烈推荐该书。)强烈推荐该书。)

Page 11: 腾讯大讲堂05 面向对象应对之道
Page 12: 腾讯大讲堂05 面向对象应对之道

好代码的近似标准介绍好代码的近似标准介绍 OOOO (或者说语言)的核心思想(或者说语言)的核心思想 OOOO 的五大技术原则(标准)的五大技术原则(标准) 从从 OOOO 看合理的分层架构看合理的分层架构

Page 13: 腾讯大讲堂05 面向对象应对之道

OO(OO( 或者说语言或者说语言 )) 的核心思想—表的核心思想—表达领域概念达领域概念

语言的语法都是比较简单的。不过同语言的语法都是比较简单的。不过同样的语法写出来的代码却有好坏高低样的语法写出来的代码却有好坏高低之分。之分。

重要的区别就在于重要的区别就在于表达领域概念的水表达领域概念的水平平

重要的原则就是重要的原则就是 :“:“ 程序(代码)应该程序(代码)应该反映人的思想,而不是相反。” 反映人的思想,而不是相反。” MartiMartin fowler.n fowler. (《分析模式》)(《分析模式》)

Page 14: 腾讯大讲堂05 面向对象应对之道
Page 15: 腾讯大讲堂05 面向对象应对之道

如何来表达一个如何来表达一个 mmog-mmog- 静态视图?静态视图?

Page 16: 腾讯大讲堂05 面向对象应对之道

针对某个领域对象粗分操作,行为,针对某个领域对象粗分操作,行为,职责。职责。

Page 17: 腾讯大讲堂05 面向对象应对之道

通过对领域概念应用通过对领域概念应用 OOOO 原则,分原则,分析模式,设计模式等等手段对对象析模式,设计模式等等手段对对象职责进行抽象,细分职责。形成最职责进行抽象,细分职责。形成最终静态对象图。终静态对象图。

通过对用例画时序图,确认对象职通过对用例画时序图,确认对象职责是否可行,恰当。责是否可行,恰当。

Page 18: 腾讯大讲堂05 面向对象应对之道

Object

WorldObject

Unit

Creature

Pet Totem

Player

基本的容器类抽象类int 型float 型GUID管理

有位置的东西.管理坐标3D距离水平距离

有HP的东西.有hp 就会有level,armor,被攻击,被施法,有路径,甚至可能有技能。这个层次开始变得复杂。所以想以聚合的形式实现。这一层的实现和mangos不同。但总体来看是表达同样的概念。

MaNGoS Structure

corpse

有智能的东西

Page 19: 腾讯大讲堂05 面向对象应对之道

实际实际 mmogAImmogAI 表达的例子表达的例子

+Enter()+Update()+Exit()+OnMetPlayer()+OnBeHit()+OnMoveEnd()

state

巡逻 战斗 逃跑 拾取

+ShouldAttack()+ShouldEscape()+ShouldPickUp()

IPolicy

+AttackStart()+AttackEnd()+Update()

IActionImp

GlobalState

实现与状态无关的行为变化需求。

描述一个怪物的个性。

+Update()

IMovementGenerator实现目标点的产生

Page 20: 腾讯大讲堂05 面向对象应对之道

表达概念的几种类型表达概念的几种类型 释意接口。 释意接口。 表达实体对象表达实体对象 表达约束表达约束 表达流程表达流程 (( 服务服务 )) 表达规格 表达规格 隐含机制表达隐含机制表达

Page 21: 腾讯大讲堂05 面向对象应对之道

““ 在初学面向对象时对它们并不熟悉。每在初学面向对象时对它们并不熟悉。每学会一个这样的表达的类型,我的设计水学会一个这样的表达的类型,我的设计水平就又进了一步” “平就又进了一步” “ My designs became shMy designs became sharper with each one of these I leaned.”arper with each one of these I leaned.”

Eric Evans Eric Evans 《领域驱动设计》强烈推荐该书《领域驱动设计》强烈推荐该书

Page 22: 腾讯大讲堂05 面向对象应对之道

释意接口的例子释意接口的例子 int CPlayer::StandUp( int iSessionID )int CPlayer::StandUp( int iSessionID ) {{ int iOpenNum = 0;int iOpenNum = 0; iOpenNum = m_Sessions.GetLastIdx();iOpenNum = m_Sessions.GetLastIdx();

//// 下面两个判断判断违法情况。下面两个判断判断违法情况。 if( iSessionID < 0if( iSessionID < 0 )) {{ }}

else if(iSessionID > iOpenNum)else if(iSessionID > iOpenNum) {{ } }

}}

Page 23: 腾讯大讲堂05 面向对象应对之道

推荐写法如下:推荐写法如下: RoomSession RoomSession 提取成一个提取成一个对象(类),对象(类),提提供供 CheckRoomIDValidCheckRoomIDValid 接口。接口。

int CPlayer::StandUp( int iSessionID )int CPlayer::StandUp( int iSessionID ) {{

iRet = iRet = m_Session.CheckValid(iSessionID);m_Session.CheckValid(iSessionID);

If(iRet)If(iRet)

{{

}} }}

Page 24: 腾讯大讲堂05 面向对象应对之道

这种是完全达到了隐藏实现,消除了代码这种是完全达到了隐藏实现,消除了代码重复,又充分表意的目的。特别在此强调重复,又充分表意的目的。特别在此强调释意接口。释意接口。

好的类 应该是每个函数都比较短,五,六好的类 应该是每个函数都比较短,五,六十行。然后有二,三十个方法。这个类形十行。然后有二,三十个方法。这个类形成一个接近封闭的类型。具有充分的自我成一个接近封闭的类型。具有充分的自我表达能力。表达能力。

Page 25: 腾讯大讲堂05 面向对象应对之道

实体表达的例子实体表达的例子 char sNowDate[20]={0};char sNowDate[20]={0}; char sLastDate[20]={0};char sLastDate[20]={0}; GetDate(time(NULL),sNowDate);GetDate(time(NULL),sNowDate); GetDate(iReserve[LastGive], sLastDate);GetDate(iReserve[LastGive], sLastDate); if(strcmp(sNowDate, sLastDate) > 0)if(strcmp(sNowDate, sLastDate) > 0) {{ }} elseelse {{ }}

Page 26: 腾讯大讲堂05 面向对象应对之道

同一个功能的另外一种写法 也是实际代码。同一个功能的另外一种写法 也是实际代码。 int CGiveDaily::OnGive(CAttach *pPA, int iHE)int CGiveDaily::OnGive(CAttach *pPA, int iHE) {{ Date dToday(time(NULL));Date dToday(time(NULL)); Date dLastDay(pPA->GetGiveHELastTime());Date dLastDay(pPA->GetGiveHELastTime());

if(dLastDay == dToday)if(dLastDay == dToday) {{ }} elseelse {{ }} }}

Page 27: 腾讯大讲堂05 面向对象应对之道

可以看出 抽取出了 日期类,用日期类 来表可以看出 抽取出了 日期类,用日期类 来表达人的思想,而不是只记得使用哪个达人的思想,而不是只记得使用哪个 APIAPI来实现功能。来实现功能。

日期这个概念在这个需求里面是比较重要日期这个概念在这个需求里面是比较重要的一个概念。面向对象就表达出了这个概的一个概念。面向对象就表达出了这个概念念。。

Page 28: 腾讯大讲堂05 面向对象应对之道

约束表达的例子约束表达的例子 有时候某些约束表达的是领域逻辑。通常有时候某些约束表达的是领域逻辑。通常

隐式的表达,将他们显示表达出来能够极隐式的表达,将他们显示表达出来能够极大地改进设计。大地改进设计。

比如比如 QQGame QQGame 里面进入房间限制。里面进入房间限制。

Page 29: 腾讯大讲堂05 面向对象应对之道

实际产品对进房需求的演化实际产品对进房需求的演化 第一个版本第一个版本 ::限制一下玩家最低,最高积分。限制一下玩家最低,最高积分。 第二个版本超级玩家和网管要优先进房第二个版本超级玩家和网管要优先进房 第三个版本如果是出租房间需要是承租方第三个版本如果是出租房间需要是承租方才能进房才能进房

第四个版本如果是比赛房间需要是比赛方第四个版本如果是比赛房间需要是比赛方才能进房才能进房

第五个版本需要拥有某种道具第五个版本需要拥有某种道具 第六个版本如果是欢乐场房间需要检查欢第六个版本如果是欢乐场房间需要检查欢乐豆上下限制。乐豆上下限制。

Page 30: 腾讯大讲堂05 面向对象应对之道
Page 31: 腾讯大讲堂05 面向对象应对之道

+Check(int iRoomID,int iPlayerID)()+Next()

IEnterRoomRule

CCheckPointRule CCheckIdentityRule CCheckRentRole

Page 32: 腾讯大讲堂05 面向对象应对之道

产品的需求演化说明进房约束是个热产品的需求演化说明进房约束是个热点问题。点问题。

抽象出约束接口,把约束的增加,约抽象出约束接口,把约束的增加,约束的实现,变更对束的实现,变更对进房主流程进房主流程屏蔽起屏蔽起来。来。

Page 33: 腾讯大讲堂05 面向对象应对之道

流程流程 (( 服务服务 )) 表达的例子表达的例子

CPlayer CTable CRoom

角色

坐下

IsFeasible

IsFeasible

Sitdown

IsFeasible

Sitdown

Page 34: 腾讯大讲堂05 面向对象应对之道

基本行为流程概念的表达,对于产品同事不断提及基本行为流程概念的表达,对于产品同事不断提及到的流程概念表达。到的流程概念表达。

主角1

Sitdown CPlayer CTable CRoom

IsFeasible

IsFeasible

Sitdown

Sitdwon

Sitdown

Page 35: 腾讯大讲堂05 面向对象应对之道

行为概念流程表达的好处行为概念流程表达的好处

主角1

CRoom坐下

普通坐下,检查玩家各自的设置,比如网速等

混战房间,预分配座位.随机选择一个座位让用户坐下

混战房间,统一撮合机制 加入等待撮合的队列

比赛房间 指定座位,到指定座位坐下

Page 36: 腾讯大讲堂05 面向对象应对之道

把规格用对象来表达把规格用对象来表达 验证。验证。 选择选择 (( 查询查询 )) 按需创建按需创建

Page 37: 腾讯大讲堂05 面向对象应对之道

隐含概念表达实例隐含概念表达实例 在在 QQGameQQGame 里面对房间模式的描述结构如里面对房间模式的描述结构如

下。不同的房间模式,具有不一样的基本下。不同的房间模式,具有不一样的基本行为。行为。

我们通过不同的工厂实现来屏蔽掉这一层我们通过不同的工厂实现来屏蔽掉这一层变化。不同的房间聚合不同的生成工厂。变化。不同的房间聚合不同的生成工厂。

房间模式是挖掘出来的概念,抽象工厂表房间模式是挖掘出来的概念,抽象工厂表达出了这个概念。达出了这个概念。

Page 38: 腾讯大讲堂05 面向对象应对之道

CRoom

1

1

+CreateSitDownAction()+CreateStandup()+CreateEnterRoom()+CreateLeaveRoom()+CreateStartGame()+CreateOnGameEnd()+CreateOnGameStart()+CreateSetGameScoreAcion()

IActionFatory

CCommonRoomFatory CCompetionRoomFactory CDogFightRoomFactory

Page 39: 腾讯大讲堂05 面向对象应对之道

OOOO 的五项技术原则是什么?(讨论,的五项技术原则是什么?(讨论,提问)提问)

Page 40: 腾讯大讲堂05 面向对象应对之道
Page 41: 腾讯大讲堂05 面向对象应对之道

OOOO 的五项技术原则的五项技术原则 单一职责—事情不要太复杂。单一职责—事情不要太复杂。 开闭原则—让易变的容易变化,不变的稳开闭原则—让易变的容易变化,不变的稳定。定。

依赖倒置—让易变的依赖于稳定,而不是依赖倒置—让易变的依赖于稳定,而不是相反。相反。

接口隔离接口隔离 可替代可替代

Page 42: 腾讯大讲堂05 面向对象应对之道

OCP(Open-Closed Principle) : OCP(Open-Closed Principle) : 开放开放 -- 关闭原则关闭原则 对扩展要说对扩展要说 YESYES ,对修改说,对修改说 NONO 。。 LSP(Liskov Substitution Principle) : LSPLSP(Liskov Substitution Principle) : LSP 原则原则 父母要对孩子负责。父母要对孩子负责。

SRP(Single Responsibility Principle) : SRP(Single Responsibility Principle) : 单一职责原单一职责原则则

感情要单一,不要脚踏两支船。感情要单一,不要脚踏两支船。DIP(Dependency Inversion Principle) : DIP(Dependency Inversion Principle) : 关系返转原关系返转原则则不要一天打不要一天打 1010 个电话给我,有结果我会通知你。个电话给我,有结果我会通知你。ISP(Interface Segregation Principle) : ISP(Interface Segregation Principle) : 接口隔离原则接口隔离原则让李部长只负责开发吧,市场就让辛部长做吧让李部长只负责开发吧,市场就让辛部长做吧

Page 43: 腾讯大讲堂05 面向对象应对之道

学习面向对象中最主要的一点就是,理解学习面向对象中最主要的一点就是,理解面向对象原则。如果你还没有真正理解这面向对象原则。如果你还没有真正理解这些原则,那你做出的设计可能不是最好的些原则,那你做出的设计可能不是最好的设计,那你学习设计模式也不能真正理解设计,那你学习设计模式也不能真正理解它的真谛。它的真谛。

Page 44: 腾讯大讲堂05 面向对象应对之道

五项技术原则实例五项技术原则实例 -- 单一职责单一职责 实际代码例子实际代码例子 class CDBCtrlclass CDBCtrl {{ public:public: CDBCtrl();CDBCtrl(); ~CDBCtrl();~CDBCtrl();

int Initialize(const char *szCfgFile);int Initialize(const char *szCfgFile); int PrepareToRun();int PrepareToRun(); int Run();int Run();

void* operator new(size_t nSize);void* operator new(size_t nSize); void operator delete( void* pMem);void operator delete( void* pMem);

static int CountSize();static int CountSize(); static CSharedMem *pCurrentShm;static CSharedMem *pCurrentShm; private:private: int ReadCfg(const char *szCfgFile);int ReadCfg(const char *szCfgFile); int LoadProxyCfgFromFile(char *szProxyFile, int& iProxyNumber);int LoadProxyCfgFromFile(char *szProxyFile, int& iProxyNumber); int LoadGivenRuleFromFile(char *szRuleFile, int& iRuleCount);int LoadGivenRuleFromFile(char *szRuleFile, int& iRuleCount); int LoadForbidRuleFromFile(char *szRuleFile, int& iRuleCount);int LoadForbidRuleFromFile(char *szRuleFile, int& iRuleCount); int ReadPublicCfg(const char *szCfgFile);int ReadPublicCfg(const char *szCfgFile); int LoadCreditConfig(const char *szCfgFile);int LoadCreditConfig(const char *szCfgFile); int CheckRunFlags();int CheckRunFlags(); int ConnectToProxys();int ConnectToProxys(); int CheckAndDispatchInputMsg();int CheckAndDispatchInputMsg(); int RoutineCheck();int RoutineCheck(); int DispatchOneCode(short nCodeLength, BYTE* pbyCode);int DispatchOneCode(short nCodeLength, BYTE* pbyCode); int PostInternalMsgToHandle(int iHandleID, CMsg *pMsg);int PostInternalMsgToHandle(int iHandleID, CMsg *pMsg);

int NofityDBHandles(CMsg *stMsg) ;int NofityDBHandles(CMsg *stMsg) ; TDBCfg m_stDBCfg;TDBCfg m_stDBCfg; CTCPConn m_astProxyConn[MAXPROXYNUMBER];CTCPConn m_astProxyConn[MAXPROXYNUMBER];

CDBHandle* m_apHandles[MAXHANDLENUMBER];CDBHandle* m_apHandles[MAXHANDLENUMBER];

int m_iUdpSoket ; int m_iUdpSoket ;

CASqlExe* m_apExecers[MAXHANDLENUMBER];CASqlExe* m_apExecers[MAXHANDLENUMBER]; CExceptionTab m_stExceptionTable;CExceptionTab m_stExceptionTable; };};

Page 45: 腾讯大讲堂05 面向对象应对之道

class CMainCtrlclass CMainCtrl {{ public:public:

CMainCtrl();CMainCtrl(); virtual ~CMainCtrl();virtual ~CMainCtrl();

virtual int Initialize();virtual int Initialize(); virtual int Run();virtual int Run();

int ReloadCfg();int ReloadCfg(); int CheckRunFlag();int CheckRunFlag(); protected:protected: private:private: };};

Page 46: 腾讯大讲堂05 面向对象应对之道

职责表达了负责的变化,有多个维度职责表达了负责的变化,有多个维度的职责,就有多个维度的变化的职责,就有多个维度的变化

Page 47: 腾讯大讲堂05 面向对象应对之道

五项技术原则实例五项技术原则实例 -- 开闭原则开闭原则 QQGame QQGame 最经典的例子,最经典的例子, Main FrameMain Frame 可以不可以不

动代码,游戏服务可以源源不断输出新的游动代码,游戏服务可以源源不断输出新的游戏。觉得这个是最核心的规则。戏。觉得这个是最核心的规则。(下图引用(下图引用自自 zengyuzengyu 《《 QQGameQQGame 服务器架构技术》)服务器架构技术》)

Table

Game

GetInfoSendDataSetInfo

。。。

OnEnterOnExit

OnReady

ITable

IGame

Main Server Process

Main Frame

Shared Object

。。。

Page 48: 腾讯大讲堂05 面向对象应对之道

五项技术原则实例五项技术原则实例 -- 依赖倒置依赖倒置 问题界面控件,比如问题界面控件,比如 Button,ListBoxButton,ListBox ,等。,等。

它们都是想做成通用的,也就是说和业务它们都是想做成通用的,也就是说和业务逻辑不相关。但是事件响应 是通过界面控逻辑不相关。但是事件响应 是通过界面控件传递到逻辑的。件传递到逻辑的。

问怎么做到界面控件和业务逻辑隔离?问怎么做到界面控件和业务逻辑隔离?

Page 49: 腾讯大讲堂05 面向对象应对之道
Page 50: 腾讯大讲堂05 面向对象应对之道

IButton

+OnClick()

IClickEvent

具体业务逻辑相关

UI控件层

具体业务逻辑相关

经典的解决办法(参考经典的解决办法(参考 QQGameQQGame 大厅设计以及 《敏捷软件开发》)大厅设计以及 《敏捷软件开发》)

Page 51: 腾讯大讲堂05 面向对象应对之道

实际代码例子:实际代码例子: class CmdObserverclass CmdObserver {{ public:public: CmdObserver();CmdObserver(); virtual ~CmdObserver();virtual ~CmdObserver(); virtual int CmdDone(CCommand *pCmd,int iResult = virtual int CmdDone(CCommand *pCmd,int iResult =

CmdSucceed);CmdSucceed); };}; class MsgObserverclass MsgObserver {{ public:public: MsgObserver(){}MsgObserver(){} virtual ~MsgObserver(){}virtual ~MsgObserver(){} virtual int OnMsg(CMsg *pMsg) = 0;virtual int OnMsg(CMsg *pMsg) = 0; };};

五项技术原则实例五项技术原则实例 -- 接口隔离接口隔离

Page 52: 腾讯大讲堂05 面向对象应对之道

五项技术原则实例五项技术原则实例 -- 可替换可替换 子类必须能够替换掉它们的基类型。子类必须能够替换掉它们的基类型。 问题:正方形是特殊的长方形吗?问题:正方形是特殊的长方形吗?

Page 53: 腾讯大讲堂05 面向对象应对之道

从从 OOOO 看合理的分层结构看合理的分层结构

用户界面层

* *

* *

* *

应用层

领域层

基础设施层

依赖

<<extends>>

<<extends>>

Page 54: 腾讯大讲堂05 面向对象应对之道

用户界面层:负责向用户显示信息,解析用户命用户界面层:负责向用户显示信息,解析用户命令。不一定面对的是人,可能是一条狗。令。不一定面对的是人,可能是一条狗。

应用层:定义软件可以完成的工作,指挥具有丰应用层:定义软件可以完成的工作,指挥具有丰富含义的领域对象来解决问题。这个层要保持简富含义的领域对象来解决问题。这个层要保持简练,不包括业务规则和知识,只是给下一层相互练,不包括业务规则和知识,只是给下一层相互协作的领域对象协调任务,委托工作。协作的领域对象协调任务,委托工作。

领域层:负责表示业务概念,业务状况以及业务领域层:负责表示业务概念,业务状况以及业务规则。业务软件核心。 规则。业务软件核心。 将领域层分离出来至关重将领域层分离出来至关重要。要。

基础结构层:为上层提供通用的技术能力:应用基础结构层:为上层提供通用的技术能力:应用的消息发送,领域持久化,绘制窗口等。的消息发送,领域持久化,绘制窗口等。

Page 55: 腾讯大讲堂05 面向对象应对之道

业务层根据业务层根据 Evans DDDEvans DDD ,可以再细分为应,可以再细分为应用层和领域层两种,在业务层设计编码中,用层和领域层两种,在业务层设计编码中,大量应用大量应用 OOOO 设计原则和设计模式。设计原则和设计模式。

领域层定义:负责表达业务领域概念、业领域层定义:负责表达业务领域概念、业务状态以及业务规 则,是整个业务软件核务状态以及业务规 则,是整个业务软件核心和重点。 心和重点。

应用层定义:负责完成功能,并且协调丰应用层定义:负责完成功能,并且协调丰富的领域对象来实现功能,不能包括业务富的领域对象来实现功能,不能包括业务规则,无业务状态; 规则,无业务状态;

Page 56: 腾讯大讲堂05 面向对象应对之道

从开发每个过程看从开发每个过程看 OOOO 方法论的应方法论的应用用

1.1. 需求分析,用户活动图,软件需求规格需求分析,用户活动图,软件需求规格说明书,领域建模。说明书,领域建模。 --OOA--OOA

2.2. 概要设计概要设计 //详细设计—详细设计— OOD OOD 分析和设计分析和设计的边界很难明确分开。的边界很难明确分开。

3.3. 编码编码 //测试测试 --OOP--OOP 4.4. 发布发布 5.5. 从从 11 再循环到再循环到 44

Page 57: 腾讯大讲堂05 面向对象应对之道

需求分析需求分析 -OOA-OOA

第一步,建立用户活动图。不关注实现。第一步,建立用户活动图。不关注实现。仅关注用户流程,实体。仅关注用户流程,实体。

第二步,画实体关系图,着重类概念,类第二步,画实体关系图,着重类概念,类之间关系。之间关系。

第三步,画时序图,对关键活动,用例用第三步,画时序图,对关键活动,用例用时序图来分析职责是否合理。时序图来分析职责是否合理。

Page 58: 腾讯大讲堂05 面向对象应对之道

OOAOOA 实例实例 系统需求:考评系统。 某系统需求:考评系统。 某 XXXX 公司要建立公司要建立

一个考评系统。一个考评系统。 大体上领导考虑 要从德智体等几个方面综大体上领导考虑 要从德智体等几个方面综

合考虑。合考虑。 德包括考勤,同事意见,领导意见等;智德包括考勤,同事意见,领导意见等;智

包括技术各项指标,比如操作系统,网络,包括技术各项指标,比如操作系统,网络,领域理解等;体包括体育各项指标,比如领域理解等;体包括体育各项指标,比如羽毛球,乒乓球等。羽毛球,乒乓球等。

从这些方面给一个人打分。请用从这些方面给一个人打分。请用 OOOO 描述一描述一下这个对象系统下这个对象系统 ..

Page 59: 腾讯大讲堂05 面向对象应对之道
Page 60: 腾讯大讲堂05 面向对象应对之道

实例一:把各个实体概念及其之间关系表达出来实例一:把各个实体概念及其之间关系表达出来

role

+GetPoints()

考评

+GetPoints()

+GetPoints()

+GetPoints()

+GetPoints()

考勤

+GetPoints()

同事意见

int GetPoints(){ int point1,point2,point3; point1 = 德.GetPoints(); point2 = 体.GetPoints(); point3 = 智.GetPoints();

return point1+point2+point3;

}

**

考评系统对象系统图

Page 61: 腾讯大讲堂05 面向对象应对之道

实例二:进行抽象,使概念表达更具灵活性,和可实例二:进行抽象,使概念表达更具灵活性,和可扩展性。扩展性。

role

+GetPoints()

考评

+GetPoints()()

具体考评项

+GetPoints()()

-list : 考评

复合考评项

int GetPoints(){ list::iterator it; int sum = 0; for(it=list.begin();it!=list.end();++it) { sum += (考评)(*it).GetPoints(); } return sum;

}

考评系统对象系统图

Page 62: 腾讯大讲堂05 面向对象应对之道

设计设计 -OOD-OOD 设计模式介绍 《深入浅出设计模式》 强烈设计模式介绍 《深入浅出设计模式》 强烈

推荐此书。推荐此书。 设计模式某个环境下,对某个设计问题的设计模式某个环境下,对某个设计问题的

一种解决方式的描述。一种解决方式的描述。 设计模式强调设计模式强调把容易变化和不变部分分离把容易变化和不变部分分离。。让变化部分容易变化。让变化部分容易变化。

在日常开发中,找到变化点,积累变化面在日常开发中,找到变化点,积累变化面是重要的。是重要的。

Page 63: 腾讯大讲堂05 面向对象应对之道

模板方法模板方法 观察者观察者 抽象工厂抽象工厂 桥桥 职责链职责链 组合组合 ReactorReactor acac

Page 64: 腾讯大讲堂05 面向对象应对之道

设计模式实例—模板方法设计模式实例—模板方法 在一个框架里面,比如在一个框架里面,比如 MFC,MFC, 要做本身框架要做本身框架

的初始化代码,又要给不同的业务留下初的初始化代码,又要给不同的业务留下初始化各自业务的空间。同时框架代码是以始化各自业务的空间。同时框架代码是以二进制形式发布的,不能在里面添加代码。二进制形式发布的,不能在里面添加代码。怎么办?怎么办?

一个一个 MFCMFC 应用程序的应用程序的 WinMainWinMain 函数哪里去函数哪里去了?了?

Page 65: 腾讯大讲堂05 面向对象应对之道

MFCMFC 的解决实例的解决实例

Page 66: 腾讯大讲堂05 面向对象应对之道

模板方法类图结构模板方法类图结构

+TemplateMethod()+OP1()+OP2()

AbstractClass

+OP1()+OP2()

ConcreteClass

TemplateMethod(){ .... OP1(); ..... OP2(); ...}

* *

Page 67: 腾讯大讲堂05 面向对象应对之道

设计模式实例—观察者设计模式实例—观察者 一个分层的架构,越下层的结构往往越通一个分层的架构,越下层的结构往往越通

用,下层不能依赖于上层。但是下层又有用,下层不能依赖于上层。但是下层又有东西要通知上层。比如 网络层不能依赖于东西要通知上层。比如 网络层不能依赖于领域层,问怎么能做到?领域层,问怎么能做到?

Page 68: 腾讯大讲堂05 面向对象应对之道

+registerObserver()+removeObserver()+notifyObservers()

Subject

+GetState()+SetState()

ConcreteSubject

+update()

Observer

+Update()

ConcreteObserver

观察者标准类图观察者标准类图

Page 69: 腾讯大讲堂05 面向对象应对之道

观察者实际代码例子观察者实际代码例子

class CmdObserverclass CmdObserver {{ public:public: CmdObserverCmdObserver

();(); virtual ~Cmdvirtual ~Cmd

Observer();Observer();

virtual int Cmvirtual int CmdDone(CCommand *dDone(CCommand *pCmd,int iResult = CpCmd,int iResult = CmdSucceed);mdSucceed);

};};

class CCommand class CCommand {{ public:public: CCommand();CCommand(); virtual ~CCommand();virtual ~CCommand();

virtual int RegisterObserver(CmdOvirtual int RegisterObserver(CmdObserver *pObserver);bserver *pObserver);

virtual int NotifyObserver(int iRevirtual int NotifyObserver(int iResult = CmdSucceed);sult = CmdSucceed);

private:private: CSet<CmdObserver* ,MAXOBSCSet<CmdObserver* ,MAXOBS

ERVERNUM > m_ObserverSet;ERVERNUM > m_ObserverSet; };};

这个实例中,命令是属于基础设施层的东西,但是要通知这个实例中,命令是属于基础设施层的东西,但是要通知上层业务逻辑,自己的状态变迁。所以使用观察者。上层业务逻辑,自己的状态变迁。所以使用观察者。

Page 70: 腾讯大讲堂05 面向对象应对之道

设计模式实例—抽象工厂设计模式实例—抽象工厂 OOOO 比较强调比较强调创建创建这个行为。一方面创建有这个行为。一方面创建有

时候本身很复杂;另一方面,程序很多的时候本身很复杂;另一方面,程序很多的灵活性需要通过一种合适的创建方式才能灵活性需要通过一种合适的创建方式才能获得。获得。

当当 newnew 一个对象的时候,写一个对象的时候,写 newnew 的这个代的这个代码的类就产生了对码的类就产生了对 newnew 出对象的依赖。我出对象的依赖。我们当然希望频繁变化的逻辑不要被上层依们当然希望频繁变化的逻辑不要被上层依赖。赖。

那么为了能做到这一点,就需要有合适的那么为了能做到这一点,就需要有合适的创建方式。创建方式。

Page 71: 腾讯大讲堂05 面向对象应对之道

简单的工厂简单的工厂

+Cut()+Bake()+Prepare()

Pizza

SimpleFatory

CheesePizza

PizzaUser

VeggiePizzaClamPizza

Page 72: 腾讯大讲堂05 面向对象应对之道

抽象工厂抽象工厂

CRoom

1

1

+CreateSitDownAction()+CreateStandup()+CreateEnterRoom()+CreateLeaveRoom()+CreateStartGame()+CreateOnGameEnd()+CreateOnGameStart()+CreateSetGameScoreAcion()

IActionFatory

CCommonRoomFatory CCompetionRoomFactory CDogFightRoomFactory

Page 73: 腾讯大讲堂05 面向对象应对之道

1.1. 抽象工厂强调的是一系列相关的变化聚抽象工厂强调的是一系列相关的变化聚合在一起,有几个系列,就有几个具体的合在一起,有几个系列,就有几个具体的工厂。工厂。

2.2. 切换的时候,打一个开关就可以了。使切换的时候,打一个开关就可以了。使得变化相当的容易,明显。得变化相当的容易,明显。

3.3. 工厂创建的东西互相不干扰。各干各的工厂创建的东西互相不干扰。各干各的活。活。

抽象工厂特征抽象工厂特征

Page 74: 腾讯大讲堂05 面向对象应对之道

设计模式实例—桥设计模式实例—桥 有一类模块,对外提供抽象接口,实现一有一类模块,对外提供抽象接口,实现一

个功能。它有两个维度的变化。个功能。它有两个维度的变化。 一个维度是提供的抽象功能,可能在变化。一个维度是提供的抽象功能,可能在变化。 另一个维度是实现抽象功能的实现方式也另一个维度是实现抽象功能的实现方式也

会变化。会变化。 另外一种情况是提供的抽象功能给外部接另外一种情况是提供的抽象功能给外部接

口,不希望这个接口频繁变化,给外部带口,不希望这个接口频繁变化,给外部带来困扰。来困扰。

问怎么实现这个需求?问怎么实现这个需求?

Page 75: 腾讯大讲堂05 面向对象应对之道
Page 76: 腾讯大讲堂05 面向对象应对之道

ACE Reactor-ACE Reactor- 实现视图实现视图

+RegisterHandler()+RemoveHandler()+RunReactorEventLoop()

ACE_Reactor

1 1

ACE_Reactor_Impl

ACE_Select_Reactor_Impl ACE_WFMO_Reactor

Page 77: 腾讯大讲堂05 面向对象应对之道

设计模式实例设计模式实例 -- 职责链职责链 应用层协议确定分发问题:应用层协议确定分发问题: 比如我们要分析网络上各种应用层协议内比如我们要分析网络上各种应用层协议内容。包括容。包括 smtp,http,pop3,ftpsmtp,http,pop3,ftp 等等。应用层协等等。应用层协议是会增加的。现在问题是一个网络连接,议是会增加的。现在问题是一个网络连接,我们无法知道它走的是什么协议。我们无法知道它走的是什么协议。

一个简单的端口是无法准确判断的。一个简单的端口是无法准确判断的。 问怎么做这个问题的设计方案。问怎么做这个问题的设计方案。

Page 78: 腾讯大讲堂05 面向对象应对之道
Page 79: 腾讯大讲堂05 面向对象应对之道

client

+HandleProto()

Handler

+HandleProto()+HandleHttp()

HttpHandler

+HandlerProto()+HandleFtp()

FtpHandler

-aHandler

client

+HandleProto()

-successor

HttpHandler

+HandleProto()

-successor

FtpHandler+HandleProto()

SmtpHandler

Page 80: 腾讯大讲堂05 面向对象应对之道

职责链好处如下职责链好处如下 各个协议分开,各干各的活 不会互相干扰。各个协议分开,各干各的活 不会互相干扰。

做到高内聚,低耦合。做到高内聚,低耦合。

新协议的增加是很简单的,甚至可以做到新协议的增加是很简单的,甚至可以做到动态增加。可以做到开闭原则。动态增加。可以做到开闭原则。

Page 81: 腾讯大讲堂05 面向对象应对之道

设计模式实例设计模式实例 --组合模式组合模式 请用请用 OOOO 描述描述 QQGameQQGame 的目录树结构。的目录树结构。 请在这个描述结构上计算目录树各层人数。请在这个描述结构上计算目录树各层人数。

Page 82: 腾讯大讲堂05 面向对象应对之道

Client

+GetNumber()

Node

+GetNumber()

Leaf

+GetNumber()+AddNode()+GetChild()

Composite

1

*

Page 83: 腾讯大讲堂05 面向对象应对之道

设计模式实例—设计模式实例— ReactorReactor

做许多网络服务器做许多网络服务器 //客户端的时候,基本上客户端的时候,基本上每一个都会用到每一个都会用到 selectselect 或类似功能函数。多或类似功能函数。多线程线程 // 多进程模式除外。多进程模式除外。

当当 select select 检测到某个检测到某个 fdfd 有数据的时候,我有数据的时候,我们再去读取数据。基本上这部分代码和我们再去读取数据。基本上这部分代码和我们的业务逻辑代码混合在一起。们的业务逻辑代码混合在一起。

在一个网络服务器里面,基本都需要定时在一个网络服务器里面,基本都需要定时器的操作。器的操作。

这些每一个网络服务器都需要的东西,能这些每一个网络服务器都需要的东西,能否提取出来?形成一个通用解决框架。否提取出来?形成一个通用解决框架。

Page 84: 腾讯大讲堂05 面向对象应对之道

+RegisterHandler()+RemoveHandler()+RunReactorEventLoop()

ACE_Reactor

+HandleInput()+HandleOutput()+HandleTimeout()

ACE_Event_HandlerACE_Timer_Queue

ACE_Time_Value

应用程序事件处理器

注意注意 ReactorReactor 对概念的抽象,和应用的分层隔离。对概念的抽象,和应用的分层隔离。这些经典的手段。这些经典的手段。

Page 85: 腾讯大讲堂05 面向对象应对之道

设计模式实例—异步命令模式设计模式实例—异步命令模式 高效的网络服务器高效的网络服务器 //客户端经常遇到异步操客户端经常遇到异步操作问题。作问题。

异步响应回来的时候,如何知道异步请求异步响应回来的时候,如何知道异步请求时候的状态是什么一直是个问题。时候的状态是什么一直是个问题。

这个操作超时,完成,失败和业务逻辑的这个操作超时,完成,失败和业务逻辑的隔离也存在问题。隔离也存在问题。

ACTACT 异步回调异步回调 TOKENTOKEN 的概念。的概念。

Page 86: 腾讯大讲堂05 面向对象应对之道

异步命令模式框图异步命令模式框图

+Execute()+RegisterObserver()+RemoveObserver()+GetResult()#NotifyObserver()

Cmd

+CmdDone()

Observer

CChangeMoneyCmd CChangeScoreCmd CListItemCmd

+PostMessage()

NetHandler

+OnMsg()

CMsgObserver

Page 87: 腾讯大讲堂05 面向对象应对之道

时序图时序图 将异步操作和业务逻辑隔离。将异步操作和业务逻辑隔离。 利用异步回调利用异步回调 TOKENTOKEN 找到响应消息观察找到响应消息观察

者。通用解决方式。者。通用解决方式。 利用命令保存异步操作请求时候状态。方利用命令保存异步操作请求时候状态。方便响应回来时候恢复。便响应回来时候恢复。

Page 88: 腾讯大讲堂05 面向对象应对之道

谢谢谢谢Q&AQ&A