意图:
表示一个作用于某对象结构中的各元素的操作,在不改变对象结构的前提下,可以很方便地添加新的操作。
点评:
1。该模式诞生的理由是设计类结构时考虑到了以后也许要添加新的操作,因此事先诸葛亮一把,先预留个接口accept( Visitor & v),以后可以方便地添加新的操作了。符合开闭原则:以后不用修改类对象结构,直接扩展Visitor类即可实现新增操作。
2。该模式用到了double-dispatch,说白了就是有两个虚函数,一个在对象结构中,叫做accept,另一个在Visitor中,叫做visit。有两个虚函数就说明了在运行时刻需要确定两次才能知道到底是哪个函数作用在哪个对象上,先确定对象,再确定visitor,可以想象一个二维平面,横轴是特化的对象,纵轴是具体的visitor,纵横交点就是运行时刻确定的具体的操作。
结构图:
举例:
【Context】网站的访问者有游客、一般注册用户、高级注册用户(比如付费用户)和系统管理员。不同的访问者应该看到不同的版块页面,因此当访问者访问网站时需要进行权限检查,当然了,以后还可能进行针对访问者的别的检查,比如访问session是否过期,如未注册者只允许浏览一分钟页面,一般注册者一天只能访问两个小时。
【分析】
使用CVA分析法,Commonality不变的地方是网站有四类访问者,这些访问者的角色是确定的。变化点Variability是针对访问者的操作,如权限检查、会话Session检查、xx检查。设计模式中的Visitor模式很好地满足此种需求。
系统的活动场景说明:
1.用户输入用户名和密码,点击登录按钮
2.页面发送http请求到服务器
3.服务器容器的doMethod方法中获取客户请求参数,即用户名和密码
4.查询数据库,验证用户名和密码是否合法,并生成对应的访问者对象。
5.对于合法的访问者,根据角色设置可浏览的版块页面。
本文不打算实现一个页面和服务器端代码,使用JSP页面和Servlet很容易实现一个客户端和服务器端的交互,但是本文关注于设计模式的讲解,将从上述活动场景的第4步和第5步进行设计,假设已经验证了用户的合法性,并假设生成一个普通用户和一个高级用户对象。
【设计】
系统中出现的设计类:
网站访问者们:
User类、Unregister类、PlainRegister类、AdvancedRegister类、Administrator类
网站访问者操作类:
Visitor类、PermittionCheckVisitor类
版块类:
Board类
系统的静态类结构图:
扩展思考:
User和Board之间的关系为:各个版块需要根据User的角色(普通游客、一般用户、高级用户、管理员)显现不同的版块,而四种角色可以相互转变,比如普通游客在线注册了即成为一个普通用户,此时可浏览的版块数量需要变化;一般用户由于付费申请成为了高级用户,可以浏览的版块也要变化;一般用户由于注销了变成普通游客,可浏览的版块也要变化。如此种种变化都是易因为访问者角色的变化引起,因此可以把User设计成为状态模式,四种角色对应四种状态,状态变迁中改变可浏览的版块;也可把User和Board设计成Observer模式,当User角色变化时,调用notify方法通知可浏览的Board们改变显示状态。
复合模式:
关于模式的模式即为复合模式,也可认为是模式的组合,把GoF的23种模式视为元模式,元模式间的组合即成为组合模式。比如一个对象是多个模式的公共元素,此时即为复合模式。
上述的User对象是Visitor模式和States模式或Observer模式的公共元素,此时可以视为复合模式。