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

1,271 views

Published on

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

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,271
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
35
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • 想表达面向对象的主要观念,方法和原则。 设计模式是方法层面上的东西。 在这些方法之后是面向对象的观念在支撑。 为什么这样做是好的?什么是好的标准? 想结合许多代码的例子来表明面向对象怎么来看这 2 个问题。 理解了面向对象的观念,对于方法层面的理解应该会更好一点。同时对于全局写代码时可以建立自己的原则。
  • 介绍面向对象的一般手法 , 原则和几个设计模式来。 需要 2 个小时。
  • 这个希望能够能强化。很多毕业生不能够理解一个软件要写三年 很容易把这个搞成一个短期行为。 24 小时不停机的海量用户服务 或者上千万,上亿用户使用的软件 产品 / 策划很难把握 3 个月 /6 个月后的产品规划。 持续不断的需求,一般产品 3 年后还在持续不断开发是常见的情况。
  • 第一点 比如要考虑详细的统计信息方便搜集情况和定位问题; 要考虑关键数据的安全策略; 要考虑方便的日志机制定位问题;等等。不在本文档讨论范围。
  • 细粒度结构设计关注软件需求,需求分析,关注程序内部结构设计,代码实现。 对于细粒度的开发活动,面向对象有一个体系来支撑。 OO 是一个方法论。本文档着力描述它的应对方式。
  • 腾讯大讲堂05 面向对象应对之道

    1. 1. 面向对象开发 课程开发 :penghao 2008-04-01
    2. 2. 课程目的 <ul><li>描述面向对象编程的一般性的手法,原则 和技巧 </li></ul><ul><li>工欲善其事 , 必先利其器。 </li></ul>
    3. 3. 课程大纲 <ul><li>引言 </li></ul><ul><li>面向对象的 表达方法 </li></ul><ul><li>面向对象的 五个原则 </li></ul><ul><li>面向对象的 几个设计模式 </li></ul>
    4. 4. 我们面对的是什么?
    5. 5. 这种情况下的应对之道 <ul><li>规模大且服务不断的情况下对应的非功能性需求就会要求比较多 . </li></ul><ul><li>变化多且持续变化的情况下要求程序具有良好的结构。本文档所关注的核心。 </li></ul>
    6. 6. 程序,服务具有良好结构有两个层面的考虑 <ul><li>大粒度的结构设计。关注的层面比较宏观。这一块的知识参考 《面向模式的体系结构》 卷一。本文档不关注。 </li></ul>
    7. 7. 细粒度结构设计 - 本文档关注的核心
    8. 8. 什么代码写得好?什么叫坏的代码?有标准吗? 2-5
    9. 10. 坏代码举例 <ul><li>僵化:很难对系统进行改动,因为每个改动都会迫使许多对系统其他部分的改动。 </li></ul><ul><li>脆弱:对系统的改动会导致系统综合改动的地方在概念上无关的许多地方出现问题。 </li></ul><ul><li>牢固:很难解开系统的纠结,使之成为一些可重用的组件。 </li></ul><ul><li>粘滞:做正确的事情比做错误的事情要困难。 </li></ul><ul><li>不必要的复杂:设计中包含不具有任何直接好处的基础结构。 </li></ul><ul><li>不必要的重复: </li></ul><ul><li>晦涩:很难阅读,理解。 </li></ul><ul><li>(引用于《敏捷软件开发:原则,模式与实践》 强烈推荐该书。) </li></ul>
    10. 12. 好代码的近似标准介绍 <ul><li>OO (或者说语言)的核心思想 </li></ul><ul><li>OO 的五大技术原则(标准) </li></ul><ul><li>从 OO 看合理的分层架构 </li></ul>
    11. 13. OO( 或者说语言 ) 的核心思想—表达领域概念 <ul><li>语言的语法都是比较简单的。不过同样的语法写出来的代码却有好坏高低之分。 </li></ul><ul><li>重要的区别就在于 表达领域概念的水平 </li></ul><ul><li>重要的原则就是 :“ 程序(代码)应该反映人的思想,而不是相反。” Martin fowler. (《分析模式》) </li></ul>
    12. 15. 如何来表达一个 mmog- 静态视图?
    13. 16. 针对某个领域对象粗分操作,行为,职责。
    14. 17. <ul><li>通过对领域概念应用 OO 原则,分析模式,设计模式等等手段对对象职责进行抽象,细分职责。形成最终静态对象图。 </li></ul><ul><li>通过对用例画时序图,确认对象职责是否可行,恰当。 </li></ul>
    15. 19. 实际 mmogAI 表达的例子
    16. 20. 表达概念的几种类型 <ul><li>释意接口。 </li></ul><ul><li>表达实体对象 </li></ul><ul><li>表达约束 </li></ul><ul><li>表达流程 ( 服务 ) </li></ul><ul><li>表达规格 </li></ul><ul><li>隐含机制表达 </li></ul>
    17. 21. <ul><li>“ 在初学面向对象时对它们并不熟悉。每学会一个这样的表达的类型,我的设计水平就又进了一步” “ My designs became sharper with each one of these I leaned.” </li></ul><ul><li>Eric Evans 《领域驱动设计》强烈推荐该书 </li></ul>
    18. 22. 释意接口的例子 <ul><li>int CPlayer::StandUp( int iSessionID ) </li></ul><ul><li>{ </li></ul><ul><li>int iOpenNum = 0; </li></ul><ul><li>iOpenNum = m_Sessions.GetLastIdx(); </li></ul><ul><li>// 下面两个判断判断违法情况。 </li></ul><ul><li>if( iSessionID < 0 ) </li></ul><ul><li>{ </li></ul><ul><li>} </li></ul><ul><ul><li>else if(iSessionID > iOpenNum) </li></ul></ul><ul><ul><li> { </li></ul></ul><ul><ul><li> } </li></ul></ul><ul><li>} </li></ul>
    19. 23. 推荐写法如下: <ul><li>RoomSession 提取成一个 对象(类), 提供 CheckRoomIDValid 接口。 </li></ul><ul><li>int CPlayer::StandUp( int iSessionID ) </li></ul><ul><li>{ </li></ul><ul><ul><ul><li>iRet = m_Session.CheckValid(iSessionID); </li></ul></ul></ul><ul><ul><ul><li>If(iRet) </li></ul></ul></ul><ul><ul><ul><li>{ </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><li>} </li></ul>
    20. 24. <ul><li>这种是完全达到了隐藏实现,消除了代码重复,又充分表意的目的。特别在此强调释意接口。 </li></ul><ul><li>好的类 应该是每个函数都比较短,五,六十行。然后有二,三十个方法。这个类形成一个接近封闭的类型。具有充分的自我表达能力。 </li></ul>
    21. 25. 实体表达的例子 <ul><li>char sNowDate[20]={0}; </li></ul><ul><li>char sLastDate[20]={0}; </li></ul><ul><li>GetDate(time(NULL),sNowDate); </li></ul><ul><li>GetDate(iReserve[LastGive], sLastDate); </li></ul><ul><li>if(strcmp(sNowDate, sLastDate) > 0) </li></ul><ul><li>{ </li></ul><ul><li>} </li></ul><ul><li>else </li></ul><ul><li>{ </li></ul><ul><li>} </li></ul>
    22. 26. <ul><li>同一个功能的另外一种写法 也是实际代码。 </li></ul><ul><li>int CGiveDaily::OnGive(CAttach *pPA, int iHE) </li></ul><ul><li>{ </li></ul><ul><li>Date dToday(time(NULL)); </li></ul><ul><li>Date dLastDay(pPA->GetGiveHELastTime()); </li></ul><ul><li>if(dLastDay == dToday) </li></ul><ul><li>{ </li></ul><ul><li>} </li></ul><ul><li>else </li></ul><ul><li>{ </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    23. 27. <ul><li>可以看出 抽取出了 日期类,用日期类 来表达人的思想,而不是只记得使用哪个 API 来实现功能。 </li></ul><ul><li>日期这个概念在这个需求里面是比较重要的一个概念。面向对象就表达出了这个概念 。 </li></ul>
    24. 28. 约束表达的例子 <ul><li>有时候某些约束表达的是领域逻辑。通常隐式的表达,将他们显示表达出来能够极大地改进设计。 </li></ul><ul><li>比如 QQGame 里面进入房间限制。 </li></ul>
    25. 29. 实际产品对进房需求的演化 <ul><li>第一个版本 : 限制一下玩家最低,最高积分。 </li></ul><ul><li>第二个版本超级玩家和网管要优先进房 </li></ul><ul><li>第三个版本如果是出租房间需要是承租方才能进房 </li></ul><ul><li>第四个版本如果是比赛房间需要是比赛方才能进房 </li></ul><ul><li>第五个版本需要拥有某种道具 </li></ul><ul><li>第六个版本如果是欢乐场房间需要检查欢乐豆上下限制。 </li></ul>
    26. 32. <ul><li>产品的需求演化说明进房约束是个热点问题。 </li></ul><ul><li>抽象出约束接口,把约束的增加,约束的实现,变更对 进房主流程 屏蔽起来。 </li></ul>
    27. 33. 流程 ( 服务 ) 表达的例子
    28. 34. 基本行为流程概念的表达,对于产品同事不断提及到的流程概念表达。
    29. 35. 行为概念流程表达的好处
    30. 36. 把规格用对象来表达 <ul><li>验证。 </li></ul><ul><li>选择 ( 查询 ) </li></ul><ul><li>按需创建 </li></ul>
    31. 37. 隐含概念表达实例 <ul><li>在 QQGame 里面对房间模式的描述结构如下。不同的房间模式,具有不一样的基本行为。 </li></ul><ul><li>我们通过不同的工厂实现来屏蔽掉这一层变化。不同的房间聚合不同的生成工厂。 </li></ul><ul><li>房间模式是挖掘出来的概念,抽象工厂表达出了这个概念。 </li></ul>
    32. 39. OO 的五项技术原则是什么?(讨论,提问)
    33. 41. OO 的五项技术原则 <ul><li>单一职责—事情不要太复杂。 </li></ul><ul><li>开闭原则—让易变的容易变化,不变的稳定。 </li></ul><ul><li>依赖倒置—让易变的依赖于稳定,而不是相反。 </li></ul><ul><li>接口隔离 </li></ul><ul><li>可替代 </li></ul>
    34. 42. <ul><li>OCP(Open-Closed Principle) : 开放 - 关闭原则 </li></ul><ul><li>对扩展要说 YES ,对修改说 NO 。 </li></ul><ul><li>LSP(Liskov Substitution Principle) : LSP 原则 </li></ul><ul><li>父母要对孩子负责。 </li></ul><ul><li>SRP(Single Responsibility Principle) : 单一职责原则 </li></ul><ul><li>感情要单一,不要脚踏两支船。 </li></ul><ul><li>DIP(Dependency Inversion Principle) : 关系返转原则 </li></ul><ul><li>不要一天打 10 个电话给我,有结果我会通知你。 </li></ul><ul><li>ISP(Interface Segregation Principle) : 接口隔离原则 </li></ul><ul><li>让李部长只负责开发吧,市场就让辛部长做吧 </li></ul>
    35. 43. <ul><li>学习面向对象中最主要的一点就是,理解面向对象原则。如果你还没有真正理解这些原则,那你做出的设计可能不是最好的设计,那你学习设计模式也不能真正理解它的真谛。 </li></ul>
    36. 44. 五项技术原则实例 - 单一职责 <ul><li>实际代码例子 </li></ul><ul><li>class CDBCtrl </li></ul><ul><li>{ </li></ul><ul><li>public: </li></ul><ul><li>CDBCtrl(); </li></ul><ul><li>~CDBCtrl(); </li></ul><ul><li>int Initialize(const char *szCfgFile); </li></ul><ul><li>int PrepareToRun(); </li></ul><ul><li>int Run(); </li></ul><ul><li>void* operator new(size_t nSize); </li></ul><ul><li>void operator delete( void* pMem); </li></ul><ul><li>static int CountSize(); </li></ul><ul><li>static CSharedMem *pCurrentShm; </li></ul><ul><li>private: </li></ul><ul><li>int ReadCfg(const char *szCfgFile); </li></ul><ul><li>int LoadProxyCfgFromFile(char *szProxyFile, int& iProxyNumber); </li></ul><ul><li>int LoadGivenRuleFromFile(char *szRuleFile, int& iRuleCount); </li></ul><ul><li>int LoadForbidRuleFromFile(char *szRuleFile, int& iRuleCount); </li></ul><ul><li>int ReadPublicCfg(const char *szCfgFile); </li></ul><ul><li>int LoadCreditConfig(const char *szCfgFile); </li></ul><ul><li>int CheckRunFlags(); </li></ul><ul><li>int ConnectToProxys(); </li></ul><ul><li>int CheckAndDispatchInputMsg(); </li></ul><ul><li>int RoutineCheck(); </li></ul><ul><li>int DispatchOneCode(short nCodeLength, BYTE* pbyCode); </li></ul><ul><li>int PostInternalMsgToHandle(int iHandleID, CMsg *pMsg); </li></ul><ul><li>int NofityDBHandles(CMsg *stMsg) ; </li></ul><ul><li>TDBCfg m_stDBCfg; </li></ul><ul><li>CTCPConn m_astProxyConn[MAXPROXYNUMBER]; </li></ul><ul><li>CDBHandle* m_apHandles[MAXHANDLENUMBER]; </li></ul><ul><li>int m_iUdpSoket ; </li></ul><ul><li>CASqlExe* m_apExecers[MAXHANDLENUMBER]; </li></ul><ul><li>CExceptionTab m_stExceptionTable; </li></ul><ul><li>}; </li></ul>
    37. 45. <ul><li>class CMainCtrl </li></ul><ul><li>{ </li></ul><ul><li>public: </li></ul><ul><li>CMainCtrl(); </li></ul><ul><li>virtual ~CMainCtrl(); </li></ul><ul><li>virtual int Initialize(); </li></ul><ul><li>virtual int Run(); </li></ul><ul><li>int ReloadCfg(); </li></ul><ul><li>int CheckRunFlag(); </li></ul><ul><li>protected: </li></ul><ul><li>private: </li></ul><ul><li>}; </li></ul>
    38. 46. <ul><li>职责表达了负责的变化,有多个维度的职责,就有多个维度的变化 </li></ul>
    39. 47. 五项技术原则实例 - 开闭原则 <ul><li>QQGame 最经典的例子, Main Frame 可以不动代码,游戏服务可以源源不断输出新的游戏。觉得这个是最核心的规则。 (下图引用自 zengyu 《 QQGame 服务器架构技术》) </li></ul>
    40. 48. 五项技术原则实例 - 依赖倒置 <ul><li>问题界面控件,比如 Button,ListBox ,等。它们都是想做成通用的,也就是说和业务逻辑不相关。但是事件响应 是通过界面控件传递到逻辑的。 </li></ul><ul><li>问怎么做到界面控件和业务逻辑隔离? </li></ul>
    41. 50. 经典的解决办法(参考 QQGame 大厅设计以及 《敏捷软件开发》)
    42. 51. <ul><li>实际代码例子: </li></ul><ul><li>class CmdObserver </li></ul><ul><li>{ </li></ul><ul><li>public: </li></ul><ul><li>CmdObserver(); </li></ul><ul><li>virtual ~CmdObserver(); </li></ul><ul><li>virtual int CmdDone(CCommand *pCmd,int iResult = CmdSucceed); </li></ul><ul><li>}; </li></ul><ul><li>class MsgObserver </li></ul><ul><li>{ </li></ul><ul><li>public: </li></ul><ul><li>MsgObserver(){} </li></ul><ul><li>virtual ~MsgObserver(){} </li></ul><ul><li>virtual int OnMsg(CMsg *pMsg) = 0; </li></ul><ul><li>}; </li></ul>五项技术原则实例 - 接口隔离
    43. 52. 五项技术原则实例 - 可替换 <ul><li>子类必须能够替换掉它们的基类型。 </li></ul><ul><li>问题:正方形是特殊的长方形吗? </li></ul>
    44. 53. 从 OO 看合理的分层结构
    45. 54. <ul><li>用户界面层:负责向用户显示信息,解析用户命令。不一定面对的是人,可能是一条狗。 </li></ul><ul><li>应用层:定义软件可以完成的工作,指挥具有丰富含义的领域对象来解决问题。这个层要保持简练,不包括业务规则和知识,只是给下一层相互协作的领域对象协调任务,委托工作。 </li></ul><ul><li>领域层:负责表示业务概念,业务状况以及业务规则。业务软件核心。 将领域层分离出来至关重要。 </li></ul><ul><li>基础结构层:为上层提供通用的技术能力:应用的消息发送,领域持久化,绘制窗口等。 </li></ul>
    46. 55. <ul><li>业务层根据 Evans DDD ,可以再细分为应用层和领域层两种,在业务层设计编码中,大量应用 OO 设计原则和设计模式。 </li></ul><ul><li>领域层定义:负责表达业务领域概念、业务状态以及业务规 则,是整个业务软件核心和重点。 </li></ul><ul><li>应用层定义:负责完成功能,并且协调丰富的领域对象来实现功能,不能包括业务规则,无业务状态; </li></ul>
    47. 56. 从开发每个过程看 OO 方法论的应用 <ul><li>1. 需求分析,用户活动图,软件需求规格说明书,领域建模。 --OOA </li></ul><ul><li>2. 概要设计 / 详细设计— OOD 分析和设计的边界很难明确分开。 </li></ul><ul><li>3. 编码 / 测试 --OOP </li></ul><ul><li>4. 发布 </li></ul><ul><li>5. 从 1 再循环到 4 </li></ul>
    48. 57. 需求分析 -OOA <ul><li>第一步,建立用户活动图。不关注实现。仅关注用户流程,实体。 </li></ul><ul><li>第二步,画实体关系图,着重类概念,类之间关系。 </li></ul><ul><li>第三步,画时序图,对关键活动,用例用时序图来分析职责是否合理。 </li></ul>
    49. 58. OOA 实例 <ul><li>系统需求:考评系统。 某 XX 公司要建立一个考评系统。 </li></ul><ul><li>大体上领导考虑 要从德智体等几个方面综合考虑。 </li></ul><ul><li>德包括考勤,同事意见,领导意见等;智包括技术各项指标,比如操作系统,网络,领域理解等;体包括体育各项指标,比如羽毛球,乒乓球等。 </li></ul><ul><li>从这些方面给一个人打分。请用 OO 描述一下这个对象系统 . </li></ul>
    50. 60. 实例一:把各个实体概念及其之间关系表达出来
    51. 61. 实例二:进行抽象,使概念表达更具灵活性,和可扩展性。
    52. 62. 设计 -OOD <ul><li>设计模式介绍 《深入浅出设计模式》 强烈推荐此书。 </li></ul><ul><li>设计模式某个环境下,对某个设计问题的一种解决方式的描述。 </li></ul><ul><li>设计模式强调 把容易变化和不变部分分离 。让变化部分容易变化。 </li></ul><ul><li>在日常开发中,找到变化点,积累变化面是重要的。 </li></ul>
    53. 63. <ul><li>模板方法 </li></ul><ul><li>观察者 </li></ul><ul><li>抽象工厂 </li></ul><ul><li>桥 </li></ul><ul><li>职责链 </li></ul><ul><li>组合 </li></ul><ul><li>Reactor </li></ul><ul><li>ac </li></ul>
    54. 64. 设计模式实例—模板方法 <ul><li>在一个框架里面,比如 MFC, 要做本身框架的初始化代码,又要给不同的业务留下初始化各自业务的空间。同时框架代码是以二进制形式发布的,不能在里面添加代码。怎么办? </li></ul><ul><li>一个 MFC 应用程序的 WinMain 函数哪里去了? </li></ul>
    55. 65. MFC 的解决实例
    56. 66. 模板方法类图结构
    57. 67. 设计模式实例—观察者 <ul><li>一个分层的架构,越下层的结构往往越通用,下层不能依赖于上层。但是下层又有东西要通知上层。比如 网络层不能依赖于领域层,问怎么能做到? </li></ul>
    58. 68. 观察者标准类图
    59. 69. 观察者实际代码例子 <ul><li>class CmdObserver </li></ul><ul><li>{ </li></ul><ul><li>public: </li></ul><ul><li>CmdObserver(); </li></ul><ul><li>virtual ~CmdObserver(); </li></ul><ul><li>virtual int CmdDone(CCommand *pCmd,int iResult = CmdSucceed); </li></ul><ul><li>}; </li></ul><ul><li>class CCommand </li></ul><ul><li>{ </li></ul><ul><li>public: </li></ul><ul><li>CCommand(); </li></ul><ul><li>virtual ~CCommand(); </li></ul><ul><li>virtual int RegisterObserver(CmdObserver *pObserver); </li></ul><ul><li>virtual int NotifyObserver(int iResult = CmdSucceed); </li></ul><ul><li>private: </li></ul><ul><li>CSet<CmdObserver* ,MAXOBSERVERNUM > m_ObserverSet; </li></ul><ul><li>}; </li></ul>这个实例中,命令是属于基础设施层的东西,但是要通知上层业务逻辑,自己的状态变迁。所以使用观察者。
    60. 70. 设计模式实例—抽象工厂 <ul><li>OO 比较强调 创建 这个行为。一方面创建有时候本身很复杂;另一方面,程序很多的灵活性需要通过一种合适的创建方式才能获得。 </li></ul><ul><li>当 new 一个对象的时候,写 new 的这个代码的类就产生了对 new 出对象的依赖。我们当然希望频繁变化的逻辑不要被上层依赖。 </li></ul><ul><li>那么为了能做到这一点,就需要有合适的创建方式。 </li></ul>
    61. 71. 简单的工厂
    62. 72. 抽象工厂
    63. 73. <ul><li>1. 抽象工厂强调的是一系列相关的变化聚合在一起,有几个系列,就有几个具体的工厂。 </li></ul><ul><li>2. 切换的时候,打一个开关就可以了。使得变化相当的容易,明显。 </li></ul><ul><li>3. 工厂创建的东西互相不干扰。各干各的活。 </li></ul>抽象工厂特征
    64. 74. 设计模式实例—桥 <ul><li>有一类模块,对外提供抽象接口,实现一个功能。它有两个维度的变化。 </li></ul><ul><li>一个维度是提供的抽象功能,可能在变化。 </li></ul><ul><li>另一个维度是实现抽象功能的实现方式也会变化。 </li></ul><ul><li>另外一种情况是提供的抽象功能给外部接口,不希望这个接口频繁变化,给外部带来困扰。 </li></ul><ul><li>问怎么实现这个需求? </li></ul>
    65. 76. ACE Reactor- 实现视图
    66. 77. 设计模式实例 - 职责链 <ul><li>应用层协议确定分发问题: </li></ul><ul><li>比如我们要分析网络上各种应用层协议内容。包括 smtp,http,pop3,ftp 等等。应用层协议是会增加的。现在问题是一个网络连接,我们无法知道它走的是什么协议。 </li></ul><ul><li>一个简单的端口是无法准确判断的。 </li></ul><ul><li>问怎么做这个问题的设计方案。 </li></ul>
    67. 80. 职责链好处如下 <ul><li>各个协议分开,各干各的活 不会互相干扰。做到高内聚,低耦合。 </li></ul><ul><li>新协议的增加是很简单的,甚至可以做到动态增加。可以做到开闭原则。 </li></ul>
    68. 81. 设计模式实例 - 组合模式 <ul><li>请用 OO 描述 QQGame 的目录树结构。 </li></ul><ul><li>请在这个描述结构上计算目录树各层人数。 </li></ul>
    69. 83. 设计模式实例— Reactor <ul><li>做许多网络服务器 / 客户端的时候,基本上每一个都会用到 select 或类似功能函数。多线程 / 多进程模式除外。 </li></ul><ul><li>当 select 检测到某个 fd 有数据的时候,我们再去读取数据。基本上这部分代码和我们的业务逻辑代码混合在一起。 </li></ul><ul><li>在一个网络服务器里面,基本都需要定时器的操作。 </li></ul><ul><li>这些每一个网络服务器都需要的东西,能否提取出来?形成一个通用解决框架。 </li></ul>
    70. 84. 注意 Reactor 对概念的抽象,和应用的分层隔离。这些经典的手段。
    71. 85. 设计模式实例—异步命令模式 <ul><li>高效的网络服务器 / 客户端经常遇到异步操作问题。 </li></ul><ul><li>异步响应回来的时候,如何知道异步请求时候的状态是什么一直是个问题。 </li></ul><ul><li>这个操作超时,完成,失败和业务逻辑的隔离也存在问题。 </li></ul><ul><li>ACT 异步回调 TOKEN 的概念。 </li></ul>
    72. 86. 异步命令模式框图
    73. 87. 时序图 <ul><li>将异步操作和业务逻辑隔离。 </li></ul><ul><li>利用异步回调 TOKEN 找到响应消息观察者。通用解决方式。 </li></ul><ul><li>利用命令保存异步操作请求时候状态。方便响应回来时候恢复。 </li></ul>
    74. 88. 谢谢 Q&A

    ×