行为型设计模式之访问者模式:
一、含义
访问者(一个类)访问到(接收到)各种元素(各种类)后作出相应的操作
(针对访问的对象不同(意味着可访问多个不同的对象),执行不同的操作)
二、代码说明
1.主要有两个角色
1)访问者:
访问到各个类后,对应各个类该怎么干,要做什么事情。
2)元素:
允许接受哪一类访问者访问(调用该访问者作出相应的操作),当然也有自己的业务逻辑
2.在用C实现过程中也是参考这种思想,以各种员工通过各自的访问者获得各自的信息报表举例,具体实现如下:
1)访问者模式使用场景:
2)被调用者:
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : VisitorPattern.c 5 * Description : 访问者模式 6 本文件是被访问者的实现 7 以各种员工通过各自的访问者获得各自的 8 信息举例 9 10 * Created : 2017.07.17. 11 * Author : Yu Weifeng 12 * Function List : 13 * Last Modified : 14 * History : 15 ******************************************************************************/ 16 #include"stdio.h" 17 #include"malloc.h" 18 #include"stdlib.h" 19 #include"string.h" 20 #include"VisitorPattern.h" 21 22 /***************************************************************************** 23 -Fuction : ManagerVisitor 24 -Description : 公有函数 25 -Input : 26 -Output : 27 -Return : 28 * Modify Date Version Author Modification 29 * ----------------------------------------------- 30 * 2017/07/17 V1.0.0 Yu Weifeng Created 31 ******************************************************************************/ 32 void ManagerVisitor(T_Manager *ptManagerEmployee) 33 { 34 printf("姓名:%s, 薪水:%d\r\n绩效:%s\r\n",ptManagerEmployee->tEmployee.GetName(&ptManagerEmployee->tEmployee), 35 ptManagerEmployee->tEmployee.GetSalary(&ptManagerEmployee->tEmployee),ptManagerEmployee->GetPerformance(&ptManagerEmployee->tEmployee)); 36 37 } 38 39 /***************************************************************************** 40 -Fuction : CommonEmployeeVisitor 41 -Description : 公有函数 42 -Input : 43 -Output : 44 -Return : 45 * Modify Date Version Author Modification 46 * ----------------------------------------------- 47 * 2017/07/17 V1.0.0 Yu Weifeng Created 48 ******************************************************************************/ 49 void CommonEmployeeVisitor(T_CommonEmployee *ptEmployee) 50 { 51 printf("姓名:%s, 薪水:%d\r\n工作:%s\r\n",ptEmployee->tEmployee.GetName(&ptEmployee->tEmployee), 52 ptEmployee->tEmployee.GetSalary(&ptEmployee->tEmployee),ptEmployee->GetJobContent(&ptEmployee->tEmployee)); 53 54 }
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : VisitorPattern.h 5 * Description : 访问者模式 6 7 * Created : 2017.07.17. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #ifndef VISITOR_PATTERN_H 14 #define VISITOR_PATTERN_H 15 16 struct Employee; 17 struct Manager; 18 struct CommonEmployee; 19 20 typedef struct Visitor//访问者类 21 {//C不好实现重载,暂时用定义多个的形式 22 void (*ManagerVisit)(struct Manager *ptEmployee);//访问函数 23 void (*CommonEmployeeVisit)(struct CommonEmployee *ptEmployee);//访问函数 24 25 //void (*Visit)(struct Employee *ptEmployee);//访问函数 26 }T_Visitor;//接口 27 28 typedef struct Employee 29 { 30 char *strName;//因为各个对象需要各自的空间,所以,不得已,私有数据成员放这里 31 int iSalary;//但是为保证不直接访问私有的数据成员,人为约定,访问只能通过公有函数 32 char *(*GetName)(struct Employee *ptThis);//具体函数(本层实现) 33 void (*SetName)(struct Employee *ptThis,char *i_strName);//具体函数(本层实现) 34 int (*GetSalary)(struct Employee *ptThis);//具体函数(本层实现) 35 void (*SetSalary)(struct Employee *ptThis,int i_iSalary);//具体函数(本层实现) 36 //允许的访问者,可选择具体哪个访问者//函数内部对传入参数指针强制转换 37 void (*Accept)(struct Employee *ptThis,T_Visitor i_tAcceptVisitor);//抽象函数(下一层实现) 38 }T_Employee;//员工抽象类 39 40 typedef struct CommonEmployee 41 { 42 T_Employee tEmployee; 43 char *(*GetJobContent)();//具体函数(本层实现) 44 void (*SetJobContent)(char *i_strJobContent);//具体函数(本层实现) 45 }T_CommonEmployee; 46 47 typedef struct Manager 48 { 49 T_Employee tEmployee; 50 char *(*GetPerformance)();//具体函数(本层实现) 51 void (*SetPerformance)(char *i_strPerformance);//具体函数(本层实现) 52 }T_Manager; 53 54 55 56 void ManagerVisitor(T_Manager *ptEmployee); 57 void CommonEmployeeVisitor(T_CommonEmployee *ptEmployee); 58 #define newVisitor {ManagerVisitor,CommonEmployeeVisitor} 59 60 61 char * EmployeeGetName(T_Employee *ptThis); 62 void EmployeeSetName(T_Employee *ptThis,char *i_strName); 63 int EmployeeGetSalary(T_Employee *ptThis); 64 void EmployeeSetSalary(T_Employee *ptThis,int i_iSalary); 65 66 void ManagerAccept(T_Employee *ptThis,T_Visitor i_tAcceptVisitor); 67 char * ManagerGetPerformance(); 68 void ManagerSetPerformance(char *i_strPerformance); 69 //宏定义里面内容不可修改 70 #define newManager {NULL,0,EmployeeGetName,EmployeeSetName,EmployeeGetSalary,EmployeeSetSalary,\ 71 ManagerAccept,ManagerGetPerformance,ManagerSetPerformance} 72 73 void CommonEmployeeAccept(T_Employee *ptThis,T_Visitor i_tAcceptVisitor); 74 char * CommonEmployeeGetJobContent(); 75 void CommonEmployeeSetJobContent(char *i_strJobContent); 76 //宏定义里面内容不可修改 77 #define newCommonEmployee {NULL,0,EmployeeGetName,EmployeeSetName,EmployeeGetSalary,EmployeeSetSalary,\ 78 CommonEmployeeAccept,CommonEmployeeGetJobContent,CommonEmployeeSetJobContent} 79 80 #endif
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : Employee.c 5 * Description : 员工 6 本文件是员工实现类具体的动作 7 * Created : 2017.07.17. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #include"stdio.h" 14 #include"malloc.h" 15 #include"stdlib.h" 16 #include"string.h" 17 #include"VisitorPattern.h" 18 19 /***************************************************************************** 20 -Fuction : EmployeeGetName 21 -Description : 公有函数 22 -Input : 23 -Output : 24 -Return : 25 * Modify Date Version Author Modification 26 * ----------------------------------------------- 27 * 2017/07/17 V1.0.0 Yu Weifeng Created 28 ******************************************************************************/ 29 char * EmployeeGetName(T_Employee *ptThis) 30 { 31 return ptThis->strName; 32 } 33 /***************************************************************************** 34 -Fuction : EmployeeSetName 35 -Description : 公有函数 36 -Input : 37 -Output : 38 -Return : 39 * Modify Date Version Author Modification 40 * ----------------------------------------------- 41 * 2017/07/17 V1.0.0 Yu Weifeng Created 42 ******************************************************************************/ 43 void EmployeeSetName(T_Employee *ptThis,char *i_strName) 44 { 45 ptThis->strName=i_strName; 46 } 47 48 /***************************************************************************** 49 -Fuction : EmployeeGetSalary 50 -Description : 公有函数 51 -Input : 52 -Output : 53 -Return : 54 * Modify Date Version Author Modification 55 * ----------------------------------------------- 56 * 2017/07/17 V1.0.0 Yu Weifeng Created 57 ******************************************************************************/ 58 int EmployeeGetSalary(T_Employee *ptThis) 59 { 60 return ptThis->iSalary; 61 } 62 63 /***************************************************************************** 64 -Fuction : EmployeeSetSalary 65 -Description : 公有函数 66 -Input : 67 -Output : 68 -Return : 69 * Modify Date Version Author Modification 70 * ----------------------------------------------- 71 * 2017/07/17 V1.0.0 Yu Weifeng Created 72 ******************************************************************************/ 73 void EmployeeSetSalary(T_Employee *ptThis,int i_iSalary) 74 { 75 ptThis->iSalary=i_iSalary; 76 }
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : Manager.c 5 * Description : 经理(管理类员工) 6 本文件是经理实现类具体的动作 7 * Created : 2017.07.13. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #include"stdio.h" 14 #include"malloc.h" 15 #include"stdlib.h" 16 #include"string.h" 17 #include"VisitorPattern.h" 18 19 20 21 22 static char *g_strPerformance="零"; 23 24 /***************************************************************************** 25 -Fuction : ManagerGetPerformance 26 -Description : 获取绩效 27 -Input : 28 -Output : 29 -Return : 30 * Modify Date Version Author Modification 31 * ----------------------------------------------- 32 * 2017/07/17 V1.0.0 Yu Weifeng Created 33 ******************************************************************************/ 34 char * ManagerGetPerformance() 35 { 36 return g_strPerformance; 37 } 38 39 /***************************************************************************** 40 -Fuction : ManagerSetPerformance 41 -Description : 42 -Input : 43 -Output : 44 -Return : 45 * Modify Date Version Author Modification 46 * ----------------------------------------------- 47 * 2017/07/17 V1.0.0 Yu Weifeng Created 48 ******************************************************************************/ 49 void ManagerSetPerformance(char *i_strPerformance) 50 { 51 g_strPerformance=i_strPerformance; 52 } 53 54 /***************************************************************************** 55 -Fuction : ManagerAccept 56 -Description : 57 -Input : 58 -Output : 59 -Return : 60 * Modify Date Version Author Modification 61 * ----------------------------------------------- 62 * 2017/07/17 V1.0.0 Yu Weifeng Created 63 ******************************************************************************/ 64 void ManagerAccept(T_Employee *ptThis,T_Visitor i_tAcceptVisitor) 65 { 66 i_tAcceptVisitor.ManagerVisit((T_Manager *)ptThis); 67 }
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : CommonEmployee.c 5 * Description : 普通员工(普通类员工) 6 本文件是普通员工实现类具体的动作 7 * Created : 2017.07.17. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #include"stdio.h" 14 #include"malloc.h" 15 #include"stdlib.h" 16 #include"string.h" 17 #include"VisitorPattern.h" 18 19 20 static char *g_strJobContent="无"; 21 22 /***************************************************************************** 23 -Fuction : CommonEmployeeGetJobContent 24 -Description : 获取绩效 25 -Input : 26 -Output : 27 -Return : 28 * Modify Date Version Author Modification 29 * ----------------------------------------------- 30 * 2017/07/17 V1.0.0 Yu Weifeng Created 31 ******************************************************************************/ 32 char * CommonEmployeeGetJobContent() 33 { 34 return g_strJobContent; 35 } 36 37 /***************************************************************************** 38 -Fuction : CommonEmployeeSetJobContent 39 -Description : 40 -Input : 41 -Output : 42 -Return : 43 * Modify Date Version Author Modification 44 * ----------------------------------------------- 45 * 2017/07/17 V1.0.0 Yu Weifeng Created 46 ******************************************************************************/ 47 void CommonEmployeeSetJobContent(char *i_strJobContent) 48 { 49 g_strJobContent=i_strJobContent; 50 } 51 52 /***************************************************************************** 53 -Fuction : CommonEmployeeAccept 54 -Description : 55 -Input : 56 -Output : 57 -Return : 58 * Modify Date Version Author Modification 59 * ----------------------------------------------- 60 * 2017/07/17 V1.0.0 Yu Weifeng Created 61 ******************************************************************************/ 62 void CommonEmployeeAccept(T_Employee *ptThis,T_Visitor i_tAcceptVisitor) 63 { 64 i_tAcceptVisitor.CommonEmployeeVisit((T_CommonEmployee *)ptThis); 65 }
3)执行结果:
book@book-desktop:/work/projects/test/DesignPatterns/VisitorPattern$ gcc -o VisitorPatternUsage CommonEmployee.c Employee.c Manager.c VisitorPattern.c VisitorPatternUsage.c
book@book-desktop:/work/projects/test/DesignPatterns/VisitorPattern$ ./VisitorPatternUsage
姓名:张三, 薪水:50000
绩效:基本上为负,但是会拍领导马屁啊
姓名:李四, 薪水:15000
工作:编写程序,苦逼的搬运工
4)详细代码:
https://github.com/fengweiyu/DesignThinking/tree/master/DesignPatterns/BehavioralDesignPatterns/VisitorPattern
三、使用场景
1.业务规则要求遍历多个不同的对象是,一定要考虑使用访问者模式。
这本身也是访问者模式出发点,迭代器模式只能访问(遍历)同类或同接口的数据(当然了,如果你是用instanceof,那么能访问所有的数据,这没有争论),而访问者模式是对迭代器模式的扩充,可以遍历不同的对象,然后执行不同的操作,也就是针对访问的对象不同,执行不同的操作。
2.访问者模式还有一个用途,就是充当拦截器角色
3.访问者模式是一种集中规整模式,可以很容易把一些功能进行梳理,达到最终目的---功能集中化,如一个统一的报表运算,UI展现等。
四、优点
1.符合单一职责原则
具体元素角色也就是Employee抽象类的两个子类负责数据的加载,而访问者visitor类则负责报表的展现,两个不同的职责非常明确地分离开来
2.优秀的扩展性
由于职责分开,继续增加对数据的操作是非常快捷的,例如现在要增加一份给老板的报表,这份报表格式又有所不同,直接在Visitor中增加一个方法,传递数据后进行整理打印
3.灵活性非常高
数据由访问者处理,修改访问者就能得到相应的处理
五、缺点
1.具体元素对访问者公布细节
访问者要访问一个类就必然要求这个类公布一些方法和数据,也就是访问者关注了其他类的内部细节,这时迪米特法则所不建议的。
2.具体元素变更比较困难
具体元素角色的增加,删除,修改都比较困难,就上面那个例子,想增加一个成员变量,如年龄age,Visitor就需要修改,如果Visitor是一个还好办,多个呢?业务逻辑再复杂点呢?
3.违背了依赖倒置原则
访问者依赖的具体元素,而不是抽象元素,这破坏了依赖倒置原则,特别是在面向对象的编程中,抛弃了对接口的依赖,而直接依赖实现类,扩展比较难。
六、访问者模式扩展
1.多个访问者的情况
再另外定义访问者即可,使用的时候由具体元素允许其访问(调用该访问者)
七、几种设计模式总结附图(仅供参考)