《设计模式24》-访问者模式

上传人:夏** 文档编号:567926209 上传时间:2024-07-22 格式:PPT 页数:23 大小:681.50KB
返回 下载 相关 举报
《设计模式24》-访问者模式_第1页
第1页 / 共23页
《设计模式24》-访问者模式_第2页
第2页 / 共23页
《设计模式24》-访问者模式_第3页
第3页 / 共23页
《设计模式24》-访问者模式_第4页
第4页 / 共23页
《设计模式24》-访问者模式_第5页
第5页 / 共23页
点击查看更多>>
资源描述

《《设计模式24》-访问者模式》由会员分享,可在线阅读,更多相关《《设计模式24》-访问者模式(23页珍藏版)》请在金锄头文库上搜索。

1、7访问者模式(DecoratorPattern)访问者模式解决:在访问者模式解决:在Food结构稳定的前提下,需要访问结构稳定的前提下,需要访问Food及其子类及其子类问题-Animal:Eat的实现voidAnimal:Eat(Food*food)if(Meat*m=dynamic_cast(food)_!=NULL)/animal吃吃mm-MeatFunction();elseif(Bone*b=dynamic_cast(food)_!=NULL)/animal吃吃bb-BoneFunction();1.使用了使用了if-else结构,多了不易处理结构,多了不易处理2.使用了动态类型识别和

2、向下类型转换,违背了里氏替换原则,不易扩展使用了动态类型识别和向下类型转换,违背了里氏替换原则,不易扩展3.由于由于Meat和和Bone会有不同的外部接口,难以在会有不同的外部接口,难以在Eat中形成一致的行为中形成一致的行为解决问题解决方法:将解决方法:将Eat行为的实现,移到行为的实现,移到Food及其子类中,并在子类中给出不及其子类中,并在子类中给出不同的实现。同的实现。问题-解决全部问题了吗1.如果Animal也有子类,如Tiger和Dog类呢2.如果Animal系列增加一个Cook(Food*)操作呢?增加子类Tiger和DogvoidMeat:BeEaten(Animal*ani)

3、if(Tiger*tiger=dynamic_cast(ani)!=NULL)/meat被被tiger吃吃elseif(Dog*dog=dynamic_cast(ani)!=NULL)/meat被被dog吃吃1.又回到了初始的问题(动态类型识别和向下类型转换)!又回到了初始的问题(动态类型识别和向下类型转换)!2.增加新操作,如增加新操作,如Cook和和Store,Food的接口必须改变的接口必须改变3.Food的子类扩展的子类扩展BeEaten和和BeCooked等的实现,会造成子类数量的激等的实现,会造成子类数量的激增增问题的根源理想中的实现:voidAnimal:Eat(Food*foo

4、d)(this,food)-Eat();现实是残酷的:现实是残酷的:1.我们常用的语言我们常用的语言C/C+,Java,C#,ObjectiveC等都不支持动态双分派。等都不支持动态双分派。2.有个别语言支持动态双分派有个别语言支持动态双分派单分派和多分派决定执行哪个具体行为过程,由消息名,接收决定执行哪个具体行为过程,由消息名,接收对象,参数共同决定。对象,参数共同决定。v除消息名之外,v若由接收对象决定行为过程,称单分派;v若由接收对象和参数对象共同决定行为过程,成多分派;静态多分派(重载为例)classSomepublic:virtualvoidDo(Base&d)coutSome:Do

5、(Base&);virtualvoidDo(D1&d1)coutSome:Do(D1&);virtualvoidDo(D2&d2)coutSome:Do(D2&);;静态多分派(重载为例)classSubSome1:publicSomepublic:virtualvoidDo(Base&d)coutSumSome1:Do(Base&);virtualvoidDo(D1&d1)coutSumSome1:Do(D1&);virtualvoidDo(D2&d2)coutSumSome1:Do(D2&);;classSubSome2:publicSomepublic:virtualvoidDo(Bas

6、e&d)coutSumSome2:Do(Base&);virtualvoidDo(D1&d1)coutSumSome2:Do(D1&);virtualvoidDo(D2&d2)coutSumSome2:Do(D2&);;静态多分派(重载为例)main()D1d1;D2d2;SubSome1s1;SubSome2s2;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.决定程序执

7、行哪个重载函数,是在编译时就确定的,而不是运行时刻。决定程序执行哪个重载函数,是在编译时就确定的,而不是运行时刻。2.在编译时,编译器只能识别变量的静态类型,所以重载是静态编联的。在编译时,编译器只能识别变量的静态类型,所以重载是静态编联的。3.例子说明重载可以实现多分派,但属于静态多分派例子说明重载可以实现多分派,但属于静态多分派动态单分派classHorsepublic:virtualHorse()virtualvoidName()cout马马;classWhiteHorse:publicHorsepublic:virtualvoidName()cout白马白马;classRedHorse

8、:publicHorsepublic:virtualvoidName()cout红马红马;main()WhiteHorsewh;RedHorserh;Horse&h=wh;/输出输出白马白马coutVisit(this);voidBone:BeEaten(Visitor*v)v-Visit(this);voidMeat:BeCooked(Visitor*v)v-Visit(this);voidBone:BeCooked(Visitor*v)v-Visit(this);现在现在Food中的各方法,其行为一中的各方法,其行为一致了。致了。同样的行为,起一个相同的名吧。同样的行为,起一个相同的名吧。

9、就叫就叫Accept。这样这样Food系列中的各种系列中的各种BeXXX都可以去掉了,合成一个都可以去掉了,合成一个AcceptvoidFood:Accept(Visitor&v)v.Visit(this);步骤3/4/5-说明v步骤2中,我们采用了重载的方式定义接口。Visit(Meat*)和Visit(Bone*).v也可以采用非重载的方式定义接口,如接口为:VisitMeat(Meat*)和VisitBone(Bone*)v具体采用哪种方式定义接口,可按个人习惯v若采用非重载方式,那么子类的Accept需Override.voidMeat:Accept(Visitor&v)v.Visit

10、Meat(this);voidBone:Accept(Visitor&v)v.VisitBone(this);步骤7Animal中的实现VoidTiger:Eat(Meat*meat)Visitor*v=newTigerEatVisitor;meat-Accept(v);VoidTiger:Eat(Bone*bone)Visitor*v=newTigerEatVisitor;bone-Accept(v);VoidDog:Cook(Meat*meat)Visitor*v=newDogCookVisitor;meat-Accept(v);VoidDog:Cook(Bone*bone)Visitor

11、*v=newDogCookVisitor;bone-Accept(v);蓝色部分完全可改成:蓝色部分完全可改成:Eat(Food*food)那么那么实例化不同的实例化不同的Visitor子类子类完成的就是相应的实现。完成的就是相应的实现。Eat(Food*food)Visitor*v=newTigerEatVisitor;Food-Accept(v);Cook(Food*food)Visitor*v=newDogCookVisitor;Food-Accept(v);访问者模式效果vFood的子类数量需要稳定。否则会导致Visitor的接口变化v将对各子类不相同接口的访问,变为统一。v扩展各种访

12、问的实现容易。如从TigerXXXVisitor派生子类扩展即可。v增加新的访问容易。如增加Tiger的Store(Meat*)和Store(Bone*),只需从TigerVisitor派生新的子类TigerStoreVisitor即可。访问者模式结构例例子说明v货车、轿车、车组的属性各不相同,成员函数也不相同,即接口难以统一v计算运营费用时,使用的算法、依据、原则等总会有变化v还会增加计算保险费用,计算固定资产净值等v(货车、轿车、车组)结构稳定classVisitorpublic:virtualVisitor()virtualint计算货车计算货车(货车货车*)=0;virtualint计

13、算轿车计算轿车(轿车轿车*)=0;virtualint计算车组计算车组(车组车组*)=0;class运营费用运营费用Visitor:publicVisitorPublic:virtualint计算货车计算货车(货车货车*c)money+=c-Get载重载重()*10;virtualint计算轿车计算轿车(轿车轿车*c)money+=c-Get车龄车龄()*5;virtualint计算车组计算车组(车组车组*c)money+=c-GetTotalCount()*8;intGetMoney()constreturnmoney;Private:intmoney;void货车货车:Accept(Visitor&v)v.计算货车计算货车(this);void轿车轿车:Accept(Visitor&v)v.计算轿车计算轿车(this);void车组车组:Accept(Visitor&v)foreach车车in组内组内车车-Accept(this)v.计算车组计算车组(this);车辆车辆*车车=new货车;货车;运营费用运营费用Visitorvisitor;车车-Accept(visitor);cout“运营费用运营费用=”visitor.GetMoney()endl;

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号