Java设计模式之访问者模式

来源:互联网 发布:网易云音乐wifi无网络 编辑:程序博客网 时间:2024/05/16 13:38

一·访问者模式

         访问者模式表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
从定义可以看出结构对象是使用访问者模式的必备条件,而且这个结构对象必须存在遍历自身各个对象的方法,类似于Java中的Collection。

     访问者模式的目的是要把处理从数据结构中分离出来,如果系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式是个不错的选择,因为访问者模式使的算法操作的增加变得容易。相反,如果系统的数据结构不稳定,易于变化,则此系统就不适合使用访问者模式了。

       如果对以上的解释不是很清楚的话,通过对生活中的一个例子来解释。 你所在的公司每个月人力资源部要对所有员工进行上班时长、加班时长统计,而财务部要对所有员工进行工资核算,不同职位的员工薪资核算标准肯定不一样啊,这个大家都明白。在这个案例中人力资源部和财务部是两个不同类型的部门(访问者),所有员工(被访问者)是一个对象集合,而员工又划分为管理者和技术者两种类型(备注:这里小吕只是简单划分为两类),在每月的统计中,人力资源部需要分别对员工进行上班时长和加班时长进行统计,而财务部需要对不同职位的员工进行薪资核算,可见不同部门职责不同,及对员工的访问操作不同、每个部门对不同类型的员工的访问操作也不同。那么针对这种场景  我们有必要了解一下访问者模式。


1>、Visitor(抽象访问者):为每种具体的被访问者(ConcreteElement)声明一个访问操作;

2>、ConcreteVisitor(具体访问者):实现对被访问者(ConcreteElement)的具体访问操作;

3>、Element(抽象被访问者):通常有一个Accept方法,用来接收/引用一个抽象访问者对象;

4>、ConcreteElement(具体被访问者对象):实现Accept抽象方法,通过传入的具体访问者参数、调用具体访问者对该对象的访问操作方法实现访问逻辑;

5>、Clent、ObjectStructure(客户端访问过程测试环境):该过程中,被访问者通常为一个集合对象,通过对集合的遍历完成访问者对每一个被访问元素的访问操作;

用例学习

1.抽象被访问者:公司员工抽象类  Employee.java

[java] view plain copy
  1. /** 
  2.  * 公司员工(被访问者)抽象类 
  3.  * @author  lvzb.software@qq.com 
  4.  * 
  5.  */  
  6. public abstract class Employee {  
  7.       
  8.     /** 
  9.      * 接收/引用一个抽象访问者对象 
  10.      * @param department 抽象访问者 这里指的是公司部门如 人力资源部、财务部 
  11.      */  
  12.     public abstract void accept(Department department);  
  13.   
  14. }  
2.具体被访问者:公司管理岗位员工类 ManagerEmployee.java
[java] view plain copy
  1. /** 
  2.  * 公司员工:管理者(具体的被访问者对象) 
  3.  * @author  lvzb.software@qq.com 
  4.  *  
  5.  */  
  6. public class ManagerEmployee extends Employee {  
  7.     // 员工姓名  
  8.     private String name;  
  9.     // 每天上班时长  
  10.     private int timeSheet;   
  11.     // 每月工资  
  12.     private double wage;  
  13.     // 请假/迟到 惩罚时长  
  14.     private int punishmentTime;  
  15.       
  16.     public ManagerEmployee(String name, int timeSheet, double wage, int punishmentTime) {  
  17.         this.name = name;  
  18.         this.timeSheet = timeSheet;  
  19.         this.wage = wage;  
  20.         this.punishmentTime = punishmentTime;  
  21.     }  
  22.   
  23.       
  24.     @Override  
  25.     public void accept(Department department) {  
  26.         department.visit(this);  
  27.     }  
  28.       
  29.       
  30.     /** 
  31.      * 获取每月的上班实际时长 = 每天上班时长 * 每月上班天数 - 惩罚时长 
  32.      * @return 
  33.      */  
  34.     public int getTotalTimeSheet(){  
  35.         return timeSheet * 22 - punishmentTime;  
  36.     }  
  37.       
  38.       
  39.     /** 
  40.      * 获取每月实际应发工资 = 每月固定工资 - 惩罚时长 * 5<br/> 
  41.      * <作为公司管理者 每迟到1小时 扣5块钱> 
  42.      * @return 
  43.      */  
  44.     public double getTotalWage(){  
  45.         return wage - punishmentTime * 5;  
  46.     }  
  47.       
  48.     public String getName() {  
  49.         return name;  
  50.     }  
  51.   
  52.     public void setName(String name) {  
  53.         this.name = name;  
  54.     }  
  55.   
  56.     public double getWage() {  
  57.         return wage;  
  58.     }  
  59.   
  60.     public void setWage(double wage) {  
  61.         this.wage = wage;  
  62.     }  
  63.       
  64.     public int getPunishmentTime() {  
  65.         return punishmentTime;  
  66.     }  
  67.   
  68.     public void setPunishmentTime(int punishmentTime) {  
  69.         this.punishmentTime = punishmentTime;  
  70.     }  
  71.       
  72. }  
3.具体被访问者:公司普通岗位员工类 GeneralEmployee.java
[java] view plain copy
  1. /** 
  2.  * 公司普通员工(具体的被访问者对象) 
  3.  * @author  lvzb.software@qq.com 
  4.  * 
  5.  */  
  6. public class GeneralEmployee extends Employee {  
  7.     // 员工姓名  
  8.     private String name;  
  9.     // 每天上班时长  
  10.     private int timeSheet;  
  11.     // 每月工资  
  12.     private double wage;  
  13.     // 请假/迟到 惩罚时长  
  14.     private int punishmentTime;  
  15.   
  16.     public GeneralEmployee(String name, int timeSheet, double wage, int punishmentTime) {  
  17.         this.name = name;  
  18.         this.timeSheet = timeSheet;  
  19.         this.wage = wage;  
  20.         this.punishmentTime = punishmentTime;  
  21.     }  
  22.   
  23.     @Override  
  24.     public void accept(Department department) {  
  25.         department.visit(this);  
  26.     }  
  27.   
  28.     /** 
  29.      * 获取每月的上班实际时长 = 每天上班时长 * 每月上班天数 - 惩罚时长 
  30.      * @return 
  31.      */  
  32.     public int getTotalTimeSheet() {  
  33.         return timeSheet * 22 - punishmentTime;  
  34.     }  
  35.   
  36.     /** 
  37.      * 获取每月实际应发工资 = 每月固定工资 - 惩罚时长 * 10<br/> 
  38.      * <作为公司普通员工  每迟到1小时 扣10块钱  坑吧?  哈哈> 
  39.      *  
  40.      * @return 
  41.      */  
  42.     public double getTotalWage() {  
  43.         return wage - punishmentTime * 10;  
  44.     }  
  45.       
  46.       
  47.     public String getName() {  
  48.         return name;  
  49.     }  
  50.   
  51.     public void setName(String name) {  
  52.         this.name = name;  
  53.     }  
  54.   
  55.     public double getWage() {  
  56.         return wage;  
  57.     }  
  58.   
  59.     public void setWage(double wage) {  
  60.         this.wage = wage;  
  61.     }  
  62.   
  63.     public int getPunishmentTime() {  
  64.         return punishmentTime;  
  65.     }  
  66.   
  67.     public void setPunishmentTime(int punishmentTime) {  
  68.         this.punishmentTime = punishmentTime;  
  69.     }  
  70.   
  71. }  
4.抽象访问者:公司部门抽象类 Department.java
[java] view plain copy
  1. /** 
  2.  * 公司部门(访问者)抽象类 
  3.  * @author  lvzb.software@qq.com 
  4.  * 
  5.  */  
  6. public abstract class Department {  
  7.       
  8.     // 声明一组重载的访问方法,用于访问不同类型的具体元素(这里指的是不同的员工)    
  9.       
  10.     /** 
  11.      * 抽象方法 访问公司管理者对象<br/> 
  12.      * 具体访问对象的什么  就由具体的访问者子类(这里指的是不同的具体部门)去实现 
  13.      * @param me 
  14.      */  
  15.     public abstract void visit(ManagerEmployee me);  
  16.       
  17.     /** 
  18.      * 抽象方法 访问公司普通员工对象<br/> 
  19.      * 具体访问对象的什么  就由具体的访问者子类(这里指的是不同的具体部门)去实现 
  20.      * @param ge 
  21.      */  
  22.     public abstract void visit(GeneralEmployee ge);  
  23.   
  24. }  
5.具体访问者:公司财务部类 FADepartment.java
[java] view plain copy
  1. /** 
  2.  * 具体访问者对象:公司财务部<br/> 
  3.  * 财务部的职责就是负责统计核算员工的工资 
  4.  * @author  lvzb.software@qq.com 
  5.  * 
  6.  */  
  7. public class FADepartment extends Department {  
  8.   
  9.     /** 
  10.      * 访问公司管理者对象的每月工资 
  11.      */  
  12.     @Override  
  13.     public void visit(ManagerEmployee me) {  
  14.         double totalWage = me.getTotalWage();  
  15.         System.out.println("管理者: " + me.getName() +   
  16.                 "  固定工资 =" + me.getWage() +   
  17.                 ", 迟到时长 " + me.getPunishmentTime() + "小时"+  
  18.                 ", 实发工资="+totalWage);  
  19.     }  
  20.   
  21.     /** 
  22.      * 访问公司普通员工对象的每月工资 
  23.      */  
  24.     @Override  
  25.     public void visit(GeneralEmployee ge) {  
  26.         double totalWage = ge.getTotalWage();  
  27.         System.out.println("普通员工: " + ge.getName() +   
  28.                 "  固定工资 =" + ge.getWage() +   
  29.                 ", 迟到时长 " + ge.getPunishmentTime() + "小时"+  
  30.                 ", 实发工资="+totalWage);  
  31.     }  
  32.   
  33. }  
6.具体访问者:公司人力资源部类 HRDepartment.java
[java] view plain copy
  1. /** 
  2.  * 具体访问者对象:公司人力资源部<br/> 
  3.  * 人力资源部的职责就是负责统计核算员工的每月上班时长 
  4.  * @author  lvzb.software@qq.com 
  5.  * 
  6.  */  
  7. public class HRDepartment extends Department {  
  8.   
  9.     /** 
  10.      * 访问公司管理者对象的每月实际上班时长统计 
  11.      */  
  12.     @Override  
  13.     public void visit(ManagerEmployee me) {  
  14.         me.getTotalTimeSheet();  
  15.     }  
  16.   
  17.     /** 
  18.      * 访问公司普通员工对象的每月实际上班时长统计 
  19.      */  
  20.     @Override  
  21.     public void visit(GeneralEmployee ge) {  
  22.         ge.getTotalTimeSheet();  
  23.     }  
  24.   
  25. }  
7.客户端测试类:模拟财务部对公司员工的工资核算和访问 Client.java
[java] view plain copy
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. public class Client {  
  5.   
  6.     public static void main(String[] args) {  
  7.         List<Employee> employeeList = new ArrayList<Employee>();  
  8.         Employee mep1,mep2,gep1,gep2,gep3;  
  9.         // 管理者1  
  10.         mep1 = new ManagerEmployee("王总"82000010);  
  11.         // 管理者2  
  12.         mep2 = new ManagerEmployee("谢经理"81500015);  
  13.         // 普通员工1  
  14.         gep1 = new GeneralEmployee("小杰"880008);  
  15.         // 普通员工2  
  16.         gep2 = new GeneralEmployee("小晓"8850012);  
  17.         // 普通员工3  
  18.         gep3 = new GeneralEmployee("小虎"875000);  
  19.           
  20.         employeeList.add(mep1);  
  21.         employeeList.add(mep2);  
  22.         employeeList.add(gep1);  
  23.         employeeList.add(gep2);  
  24.         employeeList.add(gep3);  
  25.           
  26.         // 财务部 对公司员工的工资核算/访问  
  27.         FADepartment department = new FADepartment();  
  28.         for(Employee employee : employeeList){  
  29.             employee.accept(department);  
  30.         }     
  31.     }  
  32.       
  33. }  

如果要更改为人力资源部对员工的一个月的上班时长统计 则只要将上述代码中的

[java] view plain copy
  1. FADepartment department = new FADepartment();  
修改为如下即可
[java] view plain copy
  1. HRDepartment department = new HRDepartment();  
8.程序运行结果:
[plain] view plain copy
  1. 管理者: 王总  固定工资 =20000.0, 迟到时长 10小时, 实发工资=19950.0  
  2. 管理者: 谢经理  固定工资 =15000.0, 迟到时长 15小时, 实发工资=14925.0  
  3. 普通员工: 小杰  固定工资 =8000.0, 迟到时长 8小时, 实发工资=7920.0  
  4. 普通员工: 小晓  固定工资 =8500.0, 迟到时长 12小时, 实发工资=8380.0  
  5. 普通员工: 小虎  固定工资 =7500.0, 迟到时长 0小时, 实发工资=7500.0


原文出处的地方是  http://blog.csdn.net/janice0529/article/details/41151987点击打开链接















原创粉丝点击