资源描述
面向对象开发面向对象开发课程开发:penghao2008-04-01-课程目的课程目的n n描述面向对象编程的一般性的手法,原则 和技巧n n工欲善其事,必先利其器。-课程大纲课程大纲n n引言n n面向对象的表达方法n n面向对象的五个原则n n面向对象的几个设计模式-我们面对的是什么?我们面对的是什么?-这种情况下的应对之道这种情况下的应对之道n n规模大且服务不断的情况下对应的非功能性需求就会要求比较多.n n变化多且持续变化的情况下要求程序具有良好的结构。本文档所关注的核心。-程序,服务具有良好结构有两个层程序,服务具有良好结构有两个层面的考虑面的考虑n n大粒度的结构设计。关注的层面比较宏观。这一块的知识参考 面向模式的体系结构 卷一。本文档不关注。-细粒度结构设计细粒度结构设计-本文档关注的核心本文档关注的核心-什么代码写得好?什么叫坏的代码什么代码写得好?什么叫坏的代码?有标准吗?有标准吗?2-5-坏代码举例坏代码举例n n 僵化:很难对系统进行改动,因为每个改动都会僵化:很难对系统进行改动,因为每个改动都会迫使许多对系统其他部分的改动。迫使许多对系统其他部分的改动。n n脆弱:对系统的改动会导致系统综合改动的地方脆弱:对系统的改动会导致系统综合改动的地方在概念上无关的许多地方出现问题。在概念上无关的许多地方出现问题。n n牢固:很难解开系统的纠结,使之成为一些可重牢固:很难解开系统的纠结,使之成为一些可重用的组件。用的组件。n n粘滞:做正确的事情比做错误的事情要困难。粘滞:做正确的事情比做错误的事情要困难。n n不必要的复杂:设计中包含不具有任何直接好处不必要的复杂:设计中包含不具有任何直接好处的基础结构。的基础结构。n n不必要的重复:不必要的重复:n n晦涩:很难阅读,理解。晦涩:很难阅读,理解。n n(引用于敏捷软件开发:原则,模式与实践(引用于敏捷软件开发:原则,模式与实践 强烈推荐该书。)强烈推荐该书。)-好代码的近似标准介绍好代码的近似标准介绍n nOO(或者说语言)的核心思想n nOO的五大技术原则(标准)n n从OO看合理的分层架构-OO(或者说语言或者说语言)的核心思想的核心思想表达表达领域概念领域概念n n 语言的语法都是比较简单的。不过同样的语法写出来的代码却有好坏高低之分。n n重要的区别就在于表达领域概念的水平n n重要的原则就是:“程序(代码)应该反映人的思想,而不是相反。”Martin fowler.(分析模式)-如何来表达一个如何来表达一个mmog-静态视图?静态视图?-针对某个领域对象粗分操作,行为,针对某个领域对象粗分操作,行为,职责。职责。-n n通过对领域概念应用通过对领域概念应用OO原则,分析原则,分析模式,设计模式等等手段对对象职模式,设计模式等等手段对对象职责进行抽象,细分职责。形成最终责进行抽象,细分职责。形成最终静态对象图。静态对象图。n n通过对用例画时序图,确认对象职通过对用例画时序图,确认对象职责是否可行,恰当。责是否可行,恰当。-实际实际mmogAI表达的例子表达的例子-表达概念的几种类型表达概念的几种类型n n释意接口。n n表达实体对象n n表达约束n n表达流程(服务)n n表达规格 n n隐含机制表达-n n“在初学面向对象时对它们并不熟悉。每学会一个这样的表达的类型,我的设计水平就又进了一步”“My designs became sharper with each one of these I leaned.”n nEric Evans 领域驱动设计强烈推荐该书-释意接口的例子释意接口的例子释意接口的例子释意接口的例子n nint CPlayer:StandUp(int iSessionID)n nn nint iOpenNum=0;n niOpenNum=m_Sessions.GetLastIdx();n n/下面两个判断判断违法情况。n nif(iSessionID iOpenNum)else if(iSessionID iOpenNum)n n-推荐写法如下:推荐写法如下:推荐写法如下:推荐写法如下:n nRoomSession 提取成一个对象(类),提供CheckRoomIDValid 接口。n nint CPlayer:StandUp(int iSessionID)n niRet=m_Session.CheckValid(iSessionID);If(iRet)n n-n n这种是完全达到了隐藏实现,消除了代码重复,又充分表意的目的。特别在此强调释意接口。n n好的类 应该是每个函数都比较短,五,六十行。然后有二,三十个方法。这个类形成一个接近封闭的类型。具有充分的自我表达能力。-实体表达的例子实体表达的例子实体表达的例子实体表达的例子n n char sNowDate20=0;n nchar sLastDate20=0;n nGetDate(time(NULL),sNowDate);n nGetDate(iReserveLastGive,sLastDate);n nif(strcmp(sNowDate,sLastDate)0)n nn nn nelsen nn n-n n同一个功能的另外一种写法同一个功能的另外一种写法同一个功能的另外一种写法同一个功能的另外一种写法 也是实际代码。也是实际代码。也是实际代码。也是实际代码。n nint CGiveDaily:OnGive(CAttach*pPA,int iHE)int CGiveDaily:OnGive(CAttach*pPA,int iHE)n n n nDate dToday(time(NULL);Date dToday(time(NULL);n nDate dLastDay(pPA-GetGiveHELastTime();Date dLastDay(pPA-GetGiveHELastTime();n nif(dLastDay=dToday)if(dLastDay=dToday)n n n n n nelseelsen n n n n n-n n可以看出可以看出 抽取出了抽取出了 日期类,用日期类日期类,用日期类 来表来表达人的思想,而不是只记得使用哪个达人的思想,而不是只记得使用哪个API来来实现功能。实现功能。n n日期这个概念在这个需求里面是比较重要日期这个概念在这个需求里面是比较重要的一个概念。面向对象就表达出了这个概的一个概念。面向对象就表达出了这个概念念。-约束表达的例子约束表达的例子n n有时候某些约束表达的是领域逻辑。通常隐式的表达,将他们显示表达出来能够极大地改进设计。n n比如QQGame 里面进入房间限制。-实际产品对进房需求的演化实际产品对进房需求的演化实际产品对进房需求的演化实际产品对进房需求的演化n n第一个版本:限制一下玩家最低,最高积分。n n第二个版本超级玩家和网管要优先进房n n第三个版本如果是出租房间需要是承租方才能进房n n第四个版本如果是比赛房间需要是比赛方才能进房n n第五个版本需要拥有某种道具n n第六个版本如果是欢乐场房间需要检查欢乐豆上下限制。-n n产品的需求演化说明进房约束是个热点问题。n n抽象出约束接口,把约束的增加,约束的实现,变更对进房主流程屏蔽起来。-流程流程(服务服务)表达的例子表达的例子-基本行为流程概念的表达,对于产品同事不断提及基本行为流程概念的表达,对于产品同事不断提及基本行为流程概念的表达,对于产品同事不断提及基本行为流程概念的表达,对于产品同事不断提及到的流程概念表达。到的流程概念表达。到的流程概念表达。到的流程概念表达。-行为概念流程表达的好处行为概念流程表达的好处-把规格用对象来表达把规格用对象来表达n n验证。n n选择(查询)n n按需创建-隐含概念表达实例隐含概念表达实例n n在QQGame里面对房间模式的描述结构如下。不同的房间模式,具有不一样的基本行为。n n我们通过不同的工厂实现来屏蔽掉这一层变化。不同的房间聚合不同的生成工厂。n n房间模式是挖掘出来的概念,抽象工厂表达出了这个概念。-OO的五项技术原则是什么?(讨论,的五项技术原则是什么?(讨论,提问)提问)-OO的五项技术原则的五项技术原则n n单一职责事情不要太复杂。n n开闭原则让易变的容易变化,不变的稳定。n n依赖倒置让易变的依赖于稳定,而不是相反。n n接口隔离n n可替代-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):接口隔离原则接口隔离原则让李部长只负责开发吧,市场就让辛部长做吧让李部长只负责开发吧,市场就让辛部长做吧-n n学习面向对象中最主要的一点就是,理解面向对象原则。如果你还没有真正理解这些原则,那你做出的设计可能不是最好的设计,那你学习设计模式也不能真正理解它的真谛。-五项技术原则实例五项技术原则实例五项技术原则实例五项技术原则实例-单一职责单一职责单一职责单一职责n n实际代码例子实际代码例子n nclass CDBCtrlclass CDBCtrln n n npublic:public:n nCDBCtrl();CDBCtrl();n nCDBCtrl();CDBCtrl();n nint Initialize(const char*szCfgFile);int Initialize(const char*szCfgFile);n nint PrepareToRun();int PrepareToRun();n nint Run();int Run();n nvoid*operator new(size_t nSize);void*operator new(size_t nSize);n nvoid operator delete(void*pMem);void operator delete(void*pMem);n nstatic int CountSize();static int CountSize();n nstatic CSharedMem*pCurrentShm;static CSharedMem*pCurrentShm;n nprivate:private:n nint ReadCfg(const char*szCfgFile);int ReadCfg(const char*szCfgFile);n nint LoadProxyCfgFromFile(char*szProxyFile,int&iProxyNumber);int LoadProxyCfgFromFile(char*szProxyFile,int&iProxyNumber);n nint LoadGivenRuleFromFile(char*szRuleFile,int&iRuleCount);int LoadGivenRuleFromFile(char*szRuleFile,int&iRuleCount);n nint LoadForbidRuleFromFile(char*szRuleFile,int&iRuleCount);int LoadForbidRuleFromFile(char*szRuleFile,int&iRuleCount);n nint ReadPublicCfg(const char*szCfgFile);int ReadPublicCfg(const char*szCfgFile);n nint LoadCreditConfig(const char*szCfgFile);int LoadCreditConfig(const char*szCfgFile);n nint CheckRunFlags();int CheckRunFlags();n nint ConnectToProxys();int ConnectToProxys();n nint CheckAndDispatchInputMsg();int CheckAndDispatchInputMsg();n nint RoutineCheck();int RoutineCheck();n nint DispatchOneCode(short nCodeLength,BYTE*pbyCode);int DispatchOneCode(short nCodeLength,BYTE*pbyCode);n nint PostInternalMsgToHandle(int iHandleID,CMsg*pMsg);int PostInternalMsgToHandle(int iHandleID,CMsg*pMsg);n nint NofityDBHandles(CMsg*stMsg);int NofityDBHandles(CMsg*stMsg);n nTDBCfg m_stDBCfg;TDBCfg m_stDBCfg;n nCTCPConn m_astProxyConnMAXPROXYNUMBER;CTCPConn m_astProxyConnMAXPROXYNUMBER;n nCDBHandle*m_apHandlesMAXHANDLENUMBER;CDBHandle*m_apHandlesMAXHANDLENUMBER;n nint m_iUdpSoket;int m_iUdpSoket;n nCASqlExe*m_apExecersMAXHANDLENUMBER;CASqlExe*m_apExecersMAXHANDLENUMBER;n nCExceptionTab m_stExceptionTable;CExceptionTab m_stExceptionTable;n n;nn -n nclass CMainCtrlclass CMainCtrln n n npublic:public:n nCMainCtrl();CMainCtrl();n nvirtual CMainCtrl();virtual CMainCtrl();n nvirtual int Initialize();virtual int Initialize();n nvirtual int Run();virtual int Run();n n n nint ReloadCfg();int ReloadCfg();n nint CheckRunFlag();int CheckRunFlag();n nprotected:protected:n nprivate:private:n n;-n n职责表达了负责的变化,有多个维度的职责,就有多个维度的变化-五项技术原则实例五项技术原则实例-开闭原则开闭原则n nQQGame 最经典的例子,Main Frame可以不动代码,游戏服务可以源源不断输出新的游戏。觉得这个是最核心的规则。(下图引用自zengyuQQGame服务器架构技术)-五项技术原则实例五项技术原则实例-依赖倒置依赖倒置n n问题界面控件,比如Button,ListBox,等。它们都是想做成通用的,也就是说和业务逻辑不相关。但是事件响应 是通过界面控件传递到逻辑的。n n问怎么做到界面控件和业务逻辑隔离?-经典的解决办法(参考经典的解决办法(参考经典的解决办法(参考经典的解决办法(参考QQGameQQGame大厅设计以及大厅设计以及大厅设计以及大厅设计以及 敏捷软件开发)敏捷软件开发)敏捷软件开发)敏捷软件开发)-n n实际代码例子:实际代码例子:n nclass CmdObserverclass CmdObservern n n npublic:public:n nCmdObserver();CmdObserver();n nvirtual CmdObserver();virtual CmdObserver();n nvirtual int CmdDone(CCommand*pCmd,int iResult=virtual int CmdDone(CCommand*pCmd,int iResult=CmdSucceed);CmdSucceed);n n;n nclass MsgObserverclass MsgObservern n n npublic:public:n nMsgObserver()MsgObserver()n nvirtual MsgObserver()virtual MsgObserver()n nvirtual int OnMsg(CMsg*pMsg)=0;virtual int OnMsg(CMsg*pMsg)=0;n n;n n 五项技术原则实例五项技术原则实例五项技术原则实例五项技术原则实例-接口隔离接口隔离接口隔离接口隔离-五项技术原则实例五项技术原则实例-可替换可替换n n 子类必须能够替换掉它们的基类型。n n问题:正方形是特殊的长方形吗?-从从OO看合理的分层结构看合理的分层结构-n n用户界面层:负责向用户显示信息,解析用户命用户界面层:负责向用户显示信息,解析用户命令。不一定面对的是人,可能是一条狗。令。不一定面对的是人,可能是一条狗。n n应用层:定义软件可以完成的工作,指挥具有丰应用层:定义软件可以完成的工作,指挥具有丰富含义的领域对象来解决问题。这个层要保持简富含义的领域对象来解决问题。这个层要保持简练,不包括业务规则和知识,只是给下一层相互练,不包括业务规则和知识,只是给下一层相互协作的领域对象协调任务,委托工作。协作的领域对象协调任务,委托工作。n n领域层:负责表示业务概念,业务状况以及业务领域层:负责表示业务概念,业务状况以及业务规则。业务软件核心。规则。业务软件核心。将领域层分离出来至关重将领域层分离出来至关重要。要。n n基础结构层:为上层提供通用的技术能力:应用基础结构层:为上层提供通用的技术能力:应用的消息发送,领域持久化,绘制窗口等。的消息发送,领域持久化,绘制窗口等。-n n业务层根据Evans DDD,可以再细分为应用层和领域层两种,在业务层设计编码中,大量应用OO设计原则和设计模式。n n领域层定义:负责表达业务领域概念、业务状态以及业务规 则,是整个业务软件核心和重点。n n应用层定义:负责完成功能,并且协调丰富的领域对象来实现功能,不能包括业务规则,无业务状态;-从开发每个过程看从开发每个过程看OO方法论的应用方法论的应用n n1.需求分析,用户活动图,软件需求规格说明书,领域建模。-OOAn n2.概要设计/详细设计OOD 分析和设计的边界很难明确分开。n n3.编码/测试-OOPn n4.发布n n5.从1再循环到4-需求分析需求分析-OOAn n第一步,建立用户活动图。不关注实现。仅关注用户流程,实体。n n第二步,画实体关系图,着重类概念,类之间关系。n n第三步,画时序图,对关键活动,用例用时序图来分析职责是否合理。-OOA实例实例n n 系统需求:考评系统。某XX公司要建立一个考评系统。n n大体上领导考虑 要从德智体等几个方面综合考虑。n n德包括考勤,同事意见,领导意见等;智包括技术各项指标,比如操作系统,网络,领域理解等;体包括体育各项指标,比如羽毛球,乒乓球等。n n从这些方面给一个人打分。请用OO描述一下这个对象系统.-实例一:把各个实体概念及其之间关系表达出来实例一:把各个实体概念及其之间关系表达出来实例一:把各个实体概念及其之间关系表达出来实例一:把各个实体概念及其之间关系表达出来-实例二:进行抽象,使概念表达更具灵活性,和可实例二:进行抽象,使概念表达更具灵活性,和可实例二:进行抽象,使概念表达更具灵活性,和可实例二:进行抽象,使概念表达更具灵活性,和可扩展性。扩展性。扩展性。扩展性。-设计设计-OODn n设计模式介绍 深入浅出设计模式 强烈推荐此书。n n设计模式某个环境下,对某个设计问题的一种解决方式的描述。n n设计模式强调把容易变化和不变部分分离。让变化部分容易变化。n n在日常开发中,找到变化点,积累变化面是重要的。-n n模板方法n n观察者n n抽象工厂n n桥n n职责链n n组合n nReactorn nac-设计模式实例设计模式实例模板方法模板方法n n在一个框架里面,比如MFC,要做本身框架的初始化代码,又要给不同的业务留下初始化各自业务的空间。同时框架代码是以二进制形式发布的,不能在里面添加代码。怎么办?n n一个MFC应用程序的WinMain函数哪里去了?-MFCMFC的解决实例的解决实例的解决实例的解决实例-模板方法类图结构模板方法类图结构-设计模式实例设计模式实例观察者观察者n n一个分层的架构,越下层的结构往往越通用,下层不能依赖于上层。但是下层又有东西要通知上层。比如 网络层不能依赖于领域层,问怎么能做到?-观察者标准类图观察者标准类图-观察者实际代码例子观察者实际代码例子观察者实际代码例子观察者实际代码例子n nclass CmdObserverclass CmdObservern n n npublic:public:n nCmdObserver();CmdObserver();n nvirtual virtual CmdObserver();CmdObserver();n nvirtual int virtual int CmdDone(CCommaCmdDone(CCommand*pCmd,int iResult nd*pCmd,int iResult=CmdSucceed);=CmdSucceed);n n;n nclass CCommand class CCommand n n n npublic:public:n nCCommand();CCommand();n nvirtual CCommand();virtual CCommand();n n virtual int virtual int RegisterObserver(CmdObserver RegisterObserver(CmdObserver*pObserver);*pObserver);n nvirtual int NotifyObserver(int iResult virtual int NotifyObserver(int iResult=CmdSucceed);=CmdSucceed);n nprivate:private:n nCSetCmdObserver*CSet,MAXOBSERVERNUM m_ObserverSet;m_ObserverSet;n n;这个实例中,命令是属于基础设施层的东西,但是要通知这个实例中,命令是属于基础设施层的东西,但是要通知这个实例中,命令是属于基础设施层的东西,但是要通知这个实例中,命令是属于基础设施层的东西,但是要通知上层业务逻辑,自己的状态变迁。所以使用观察者。上层业务逻辑,自己的状态变迁。所以使用观察者。上层业务逻辑,自己的状态变迁。所以使用观察者。上层业务逻辑,自己的状态变迁。所以使用观察者。-设计模式实例设计模式实例抽象工厂抽象工厂n nOO比较强调创建这个行为。一方面创建有时候本身很复杂;另一方面,程序很多的灵活性需要通过一种合适的创建方式才能获得。n n当new一个对象的时候,写new的这个代码的类就产生了对new出对象的依赖。我们当然希望频繁变化的逻辑不要被上层依赖。n n那么为了能做到这一点,就需要有合适的创建方式。-简单的工厂简单的工厂-抽象工厂抽象工厂-n n1.抽象工厂强调的是一系列相关的变化聚合在一起,有几个系列,就有几个具体的工厂。n n2.切换的时候,打一个开关就可以了。使得变化相当的容易,明显。n n3.工厂创建的东西互相不干扰。各干各的活。抽象工厂特征抽象工厂特征-设计模式实例设计模式实例桥桥n n有一类模块,对外提供抽象接口,实现一个功能。它有两个维度的变化。n n一个维度是提供的抽象功能,可能在变化。n n另一个维度是实现抽象功能的实现方式也会变化。n n另外一种情况是提供的抽象功能给外部接口,不希望这个接口频繁变化,给外部带来困扰。n n问怎么实现这个需求?-ACE Reactor-实现视图实现视图-设计模式实例设计模式实例-职责链职责链n n应用层协议确定分发问题:n n比如我们要分析网络上各种应用层协议内容。包括smtp,http,pop3,ftp等等。应用层协议是会增加的。现在问题是一个网络连接,我们无法知道它走的是什么协议。n n一个简单的端口是无法准确判断的。n n问怎么做这个问题的设计方案。-职责链好处如下职责链好处如下n n各个协议分开,各干各的活 不会互相干扰。做到高内聚,低耦合。n n新协议的增加是很简单的,甚至可以做到动态增加。可以做到开闭原则。-设计模式实例设计模式实例-组合模式组合模式n n请用OO描述QQGame的目录树结构。n n请在这个描述结构上计算目录树各层人数。-设计模式实例设计模式实例Reactorn n做许多网络服务器/客户端的时候,基本上每一个都会用到select或类似功能函数。多线程/多进程模式除外。n n当select 检测到某个fd有数据的时候,我们再去读取数据。基本上这部分代码和我们的业务逻辑代码混合在一起。n n在一个网络服务器里面,基本都需要定时器的操作。n n这些每一个网络服务器都需要的东西,能否提取出来?形成一个通用解决框架。-注意注意注意注意ReactorReactor对概念的抽象,和应用的分层隔离。这对概念的抽象,和应用的分层隔离。这对概念的抽象,和应用的分层隔离。这对概念的抽象,和应用的分层隔离。这些经典的手段。些经典的手段。些经典的手段。些经典的手段。-设计模式实例设计模式实例异步命令模式异步命令模式n n高效的网络服务器/客户端经常遇到异步操作问题。n n异步响应回来的时候,如何知道异步请求时候的状态是什么一直是个问题。n n这个操作超时,完成,失败和业务逻辑的隔离也存在问题。n nACT异步回调TOKEN的概念。-异步命令模式框图异步命令模式框图-时序图时序图n n将异步操作和业务逻辑隔离。n n利用异步回调TOKEN找到响应消息观察者。通用解决方式。n n利用命令保存异步操作请求时候状态。方便响应回来时候恢复。-谢谢谢谢Q&A-
展开阅读全文