版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、7 访问者模式(Decorator Pattern)访问者模式解决:在访问者模式解决:在Food结构稳定的前提下,需要访问结构稳定的前提下,需要访问Food及其子类及其子类问题-Animal:Eat的实现void Animal:Eat(Food* food) if (Meat * m = dynamic_cast(food)_!=NULL) /animal 吃吃 m m-MeatFunction(); else if (Bone * b= dynamic_cast(food)_!=NULL) ) /animal 吃吃 b b-BoneFunction(); 1. 使用了使用了if-else结构
2、,多了不易处理结构,多了不易处理2. 使用了动态类型识别和向下类型转换,违背了里氏替换原则,不易扩展使用了动态类型识别和向下类型转换,违背了里氏替换原则,不易扩展3. 由于由于Meat和和Bone会有不同的外部接口,难以在会有不同的外部接口,难以在Eat中形成一致的行为中形成一致的行为解决问题解决方法:将解决方法:将Eat行为的实现,移到行为的实现,移到Food及其子类中,并在子类中给出不及其子类中,并在子类中给出不同的实现。同的实现。问题-解决全部问题了吗1.如果Animal也有子类,如Tiger和Dog类呢2.如果Animal系列增加一个Cook(Food * )操作呢?增加子类Tiger
3、和Dogvoid Meat:BeEaten(Animal * ani)if ( (Tiger * tiger = dynamic_cast(ani)!= NULL ) / meat 被被 tiger 吃吃 else if (Dog * dog = dynamic_cast(ani)!= NULL ) / meat 被被 dog 吃吃 1. 又回到了初始的问题(动态类型识别和向下类型转换)!又回到了初始的问题(动态类型识别和向下类型转换)!2. 增加新操作,如增加新操作,如Cook和和Store,Food的接口必须改变的接口必须改变3. Food的子类扩展的子类扩展BeEaten和和BeCook
4、ed等的实现,会造成子类数量的激等的实现,会造成子类数量的激增增问题的根源理想中的实现:void Animal:Eat(Food* food) (this,food)-Eat();现实是残酷的:现实是残酷的:1. 我们常用的语言我们常用的语言C/C+,Java,C#,Objective C等都不支持动态双分派。等都不支持动态双分派。2. 有个别语言支持动态双分派有个别语言支持动态双分派单分派和多分派 决定执行哪个具体行为过程,由消息名,接收决定执行哪个具体行为过程,由消息名,接收对象,参数共同决定。对象,参数共同决定。v 除消息名之外,v 若由接收对象决定行为过程,称单分派;v 若由接收对象和
5、参数对象共同决定行为过程, 成多分派; 静态多分派(重载为例) class Some public: virtual void Do(Base& d) cout Some:Do(Base&); virtual void Do(D1 & d1) cout Some: Do(D1&); virtual void Do(D2 & d2) cout Some: Do(D2&);;静态多分派(重载为例)class SubSome1:public Some public: virtual void Do(Base& d) coutSumSome1:D
6、o(Base&); virtual void Do(D1 & d1) coutSumSome1: Do(D1&); virtual void Do(D2 & d2) coutSumSome1: Do(D2&);;class SubSome2:public Some public: virtual void Do(Base& d) coutSumSome2:Do(Base&); virtual void Do(D1 & d1) coutSumSome2: Do(D1&); virtual void Do(D2 & d
7、2) coutSumSome2: Do(D2&);;静态多分派(重载为例)main() D1 d1; D2 d2; SubSome1 s1; SubSome2 s2; Some & obj = s2; obj.Do(d1); / 输出为:输出为: SubSome2:Do(d1&); obj.Do(d2); / 输出为:输出为: SubSome2:Do(d2&); Base & d = d1; obj.Do(d); / 输出为:输出为: SubSome2:Do(Base&);1.决定程序执行哪个重载函数,是在编译时就确定的,而不是运行时刻。决定程序
8、执行哪个重载函数,是在编译时就确定的,而不是运行时刻。2.在编译时,编译器只能识别变量的静态类型,所以重载是静态编联的。在编译时,编译器只能识别变量的静态类型,所以重载是静态编联的。3.例子说明重载可以实现多分派,但属于静态多分派例子说明重载可以实现多分派,但属于静态多分派动态单分派class Horse public: virtual Horse() virtual void Name( ) cout马马;class WhiteHorse:public Horse public:virtual void Name( ) cout白马白马;class RedHorse:public Horse
9、public:virtual void Name( ) cout红马红马;main() WhiteHorse wh; RedHorse rh; Horse& h = wh; /输出输出 白马白马 coutVisit(this);void Bone:BeEaten(Visitor * v) v-Visit (this);void Meat:BeCooked(Visitor * v) v-Visit(this);void Bone:BeCooked(Visitor * v) v-Visit (this);现在现在Food中的各方法,其行为一中的各方法,其行为一致了。致了。同样的行为,起一个
10、相同的名吧。同样的行为,起一个相同的名吧。就叫就叫Accept。这样这样Food系列中的各种系列中的各种BeXXX都可以去掉了,合成一个都可以去掉了,合成一个Acceptvoid Food:Accept(Visitor& v) v.Visit(this); 步骤3/4/5-说明v步骤2中,我们采用了重载的方式定义接口。 Visit(Meat * ) 和Visit(Bone *).v也可以采用非重载的方式定义接口,如接口为:VisitMeat(Meat*)和VisitBone(Bone*)v具体采用哪种方式定义接口,可按个人习惯v若采用非重载方式,那么子类的Accept需Override
11、. void Meat:Accept(Visitor& v) v.VisitMeat(this); void Bone:Accept(Visitor& v) v.VisitBone(this); 步骤7 Animal中的实现Void Tiger:Eat( Meat * meat) Visitor * v= new TigerEatVisitor; meat-Accept(v);Void Tiger:Eat( Bone* bone) Visitor * v= new TigerEatVisitor; bone-Accept(v);Void Dog:Cook( Meat * mea
12、t) Visitor * v= new DogCookVisitor; meat-Accept(v);Void Dog:Cook( Bone* bone) Visitor * v= new DogCookVisitor; bone-Accept(v);蓝色部分完全可改成:蓝色部分完全可改成:Eat (Food * food)那么那么实例化不同的实例化不同的Visitor子类子类完成的就是相应的实现。完成的就是相应的实现。Eat(Food * food) Visitor * v= new TigerEatVisitor;Food-Accept(v);Cook(Food * food) Visit
13、or * v= new DogCookVisitor;Food-Accept(v);访问者模式效果vFood的子类数量需要稳定。否则会导致Visitor的接口变化v将对各子类不相同接口的访问,变为统一。v扩展各种访问的实现容易。如从TigerXXXVisitor派生子类扩展即可。v增加新的访问容易。如增加Tiger的Store(Meat*)和Store(Bone *),只需从TigerVisitor派生新的子类TigerStoreVisitor即可。访问者模式结构例例子说明v货车、轿车、车组的属性各不相同,成员函数也不相同,即接口难以统一v计算运营费用时,使用的算法、依据、原则等总会有变化v还
14、会增加计算保险费用,计算固定资产净值等v(货车、轿车、车组)结构稳定class Visitor public: virtual Visitor() virtual int 计算货车计算货车 (货车货车 * ) = 0; virtual int 计算轿车计算轿车 (轿车轿车 *) = 0; virtual int 计算车组计算车组 (车组车组 *) = 0;class 运营费用运营费用Visitor:public Visitor Public: virtual int 计算货车计算货车 (货车货车 * c) money += c-Get载重载重()*10; virtual int 计算轿车计算轿车 (轿车轿车 *c) money += c-Get车龄车龄( )*5; virtual int 计算车组计算车组 (车组车组 *c) money += c-GetTotalCount()*8; int GetMoney() const return money;Private:int money; ;void 货车货车:Accept(Visitor& v) v.计算货车计算货车(this); void 轿车轿
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 商铺租赁居间合同协议2025
- 商铺租赁补充合同协议2025
- 商铺转租合同协议2025年评估版
- 平面设计兼职合同协议2025年作品归属
- 跨境电商代运营合同2025
- 2025年跨部门团队协作绩效评估考试试题及答案
- 2025及未来5年中国化妆品恒温箱市场调查、数据监测研究报告
- 塑钢门窗工程合同范本
- 商铺租金分摊合同范本
- 喷罐设备租赁合同范本
- 心理学基础智慧树知到期末考试答案章节答案2024年杭州师范大学
- 2024中国大企业税务数智化白皮书-用友毕马威
- (高清版)DZT 0248-2014 岩石地球化学测量技术规程
- 劳动实践主题班会
- 《死亡时间推断》课件
- 关节病变的康复治疗与护理
- 河池网约车巡游车考试题目
- 福特福睿斯说明书
- 【历年真题】2023年4月00688设计概论自考试卷(浙江)
- 幼儿园中班数学《坐船游览》
- 韶音供应商QSA+QPA审核-checklist-V1
评论
0/150
提交评论