JAVA设计模式之 访问者模式【Visitor Pattern】

原创 2014年11月15日 22:21:32

一、概述

    访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。在使用访问者模式时,被访问元素通常不是单独存在的,它们存储在一个集合中,这个集合被称为“对象结构”,访问者通过遍历对象结构实现对其中存储的元素的逐个操作。访问者模式是一种对象行为型模式。


二、适用场景

    当有多种类型的访问者(或是操作者) 对一组被访问者对象集合(或是对象结构)进行操作(其中对象集合也包含多种类型对象),不同的访问者类型对每一种具体的被访问者对象提供不同的访问操作,每种访问者类型对象对不同的被访问者也有不同的访问操作,那么这种场景就非常适用访问者模式。

    如果前面这几句比较绕的文字说明没看明白,那么小吕就举例一个生活中的业务场景:

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


三、UML类图


四、参与者

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

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

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

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

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


五、用例学习

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

/**
 * 公司员工(被访问者)抽象类
 * @author  lvzb.software@qq.com
 *
 */
public abstract class Employee {
	
	/**
	 * 接收/引用一个抽象访问者对象
	 * @param department 抽象访问者 这里指的是公司部门如 人力资源部、财务部
	 */
	public abstract void accept(Department department);

}
2.具体被访问者:公司管理岗位员工类 ManagerEmployee.java

/**
 * 公司员工:管理者(具体的被访问者对象)
 * @author  lvzb.software@qq.com
 * 
 */
public class ManagerEmployee extends Employee {
	// 员工姓名
	private String name;
	// 每天上班时长
	private int timeSheet; 
	// 每月工资
	private double wage;
	// 请假/迟到 惩罚时长
	private int punishmentTime;
	
	public ManagerEmployee(String name, int timeSheet, double wage, int punishmentTime) {
		this.name = name;
		this.timeSheet = timeSheet;
		this.wage = wage;
		this.punishmentTime = punishmentTime;
	}

	
	@Override
	public void accept(Department department) {
		department.visit(this);
	}
	
	
	/**
	 * 获取每月的上班实际时长 = 每天上班时长 * 每月上班天数 - 惩罚时长
	 * @return
	 */
	public int getTotalTimeSheet(){
		return timeSheet * 22 - punishmentTime;
	}
	
	
	/**
	 * 获取每月实际应发工资 = 每月固定工资 - 惩罚时长 * 5<br/>
	 * <作为公司管理者 每迟到1小时 扣5块钱>
	 * @return
	 */
	public double getTotalWage(){
		return wage - punishmentTime * 5;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getWage() {
		return wage;
	}

	public void setWage(double wage) {
		this.wage = wage;
	}
	
	public int getPunishmentTime() {
		return punishmentTime;
	}

	public void setPunishmentTime(int punishmentTime) {
		this.punishmentTime = punishmentTime;
	}
	
}
3.具体被访问者:公司普通岗位员工类 GeneralEmployee.java

/**
 * 公司普通员工(具体的被访问者对象)
 * @author  lvzb.software@qq.com
 *
 */
public class GeneralEmployee extends Employee {
    // 员工姓名
	private String name;
	// 每天上班时长
	private int timeSheet;
	// 每月工资
	private double wage;
	// 请假/迟到 惩罚时长
	private int punishmentTime;

	public GeneralEmployee(String name, int timeSheet, double wage, int punishmentTime) {
		this.name = name;
		this.timeSheet = timeSheet;
		this.wage = wage;
		this.punishmentTime = punishmentTime;
	}

	@Override
	public void accept(Department department) {
		department.visit(this);
	}

	/**
	 * 获取每月的上班实际时长 = 每天上班时长 * 每月上班天数 - 惩罚时长
	 * @return
	 */
	public int getTotalTimeSheet() {
		return timeSheet * 22 - punishmentTime;
	}

	/**
	 * 获取每月实际应发工资 = 每月固定工资 - 惩罚时长 * 10<br/>
	 * <作为公司普通员工  每迟到1小时 扣10块钱  坑吧?  哈哈>
	 * 
	 * @return
	 */
	public double getTotalWage() {
		return wage - punishmentTime * 10;
	}
	
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getWage() {
		return wage;
	}

	public void setWage(double wage) {
		this.wage = wage;
	}

	public int getPunishmentTime() {
		return punishmentTime;
	}

	public void setPunishmentTime(int punishmentTime) {
		this.punishmentTime = punishmentTime;
	}

}
4.抽象访问者:公司部门抽象类 Department.java

/**
 * 公司部门(访问者)抽象类
 * @author  lvzb.software@qq.com
 *
 */
public abstract class Department {
	
	// 声明一组重载的访问方法,用于访问不同类型的具体元素(这里指的是不同的员工)  
	
	/**
	 * 抽象方法 访问公司管理者对象<br/>
	 * 具体访问对象的什么  就由具体的访问者子类(这里指的是不同的具体部门)去实现
	 * @param me
	 */
	public abstract void visit(ManagerEmployee me);
	
	/**
	 * 抽象方法 访问公司普通员工对象<br/>
	 * 具体访问对象的什么  就由具体的访问者子类(这里指的是不同的具体部门)去实现
	 * @param ge
	 */
	public abstract void visit(GeneralEmployee ge);

}
5.具体访问者:公司财务部类 FADepartment.java

/**
 * 具体访问者对象:公司财务部<br/>
 * 财务部的职责就是负责统计核算员工的工资
 * @author  lvzb.software@qq.com
 *
 */
public class FADepartment extends Department {

	/**
	 * 访问公司管理者对象的每月工资
	 */
	@Override
	public void visit(ManagerEmployee me) {
		double totalWage = me.getTotalWage();
		System.out.println("管理者: " + me.getName() + 
				"  固定工资 =" + me.getWage() + 
				", 迟到时长 " + me.getPunishmentTime() + "小时"+
				", 实发工资="+totalWage);
	}

	/**
	 * 访问公司普通员工对象的每月工资
	 */
	@Override
	public void visit(GeneralEmployee ge) {
		double totalWage = ge.getTotalWage();
		System.out.println("普通员工: " + ge.getName() + 
				"  固定工资 =" + ge.getWage() + 
				", 迟到时长 " + ge.getPunishmentTime() + "小时"+
				", 实发工资="+totalWage);
	}

}
6.具体访问者:公司人力资源部类 HRDepartment.java

/**
 * 具体访问者对象:公司人力资源部<br/>
 * 人力资源部的职责就是负责统计核算员工的每月上班时长
 * @author  lvzb.software@qq.com
 *
 */
public class HRDepartment extends Department {

	/**
	 * 访问公司管理者对象的每月实际上班时长统计
	 */
	@Override
	public void visit(ManagerEmployee me) {
		me.getTotalTimeSheet();
	}

	/**
	 * 访问公司普通员工对象的每月实际上班时长统计
	 */
	@Override
	public void visit(GeneralEmployee ge) {
		ge.getTotalTimeSheet();
	}

}
7.客户端测试类:模拟财务部对公司员工的工资核算和访问 Client.java

import java.util.ArrayList;
import java.util.List;

public class Client {

	public static void main(String[] args) {
		List<Employee> employeeList = new ArrayList<Employee>();
		Employee mep1,mep2,gep1,gep2,gep3;
		// 管理者1
		mep1 = new ManagerEmployee("王总", 8, 20000, 10);
		// 管理者2
		mep2 = new ManagerEmployee("谢经理", 8, 15000, 15);
		// 普通员工1
		gep1 = new GeneralEmployee("小杰", 8, 8000, 8);
		// 普通员工2
		gep2 = new GeneralEmployee("小晓", 8, 8500, 12);
		// 普通员工3
		gep3 = new GeneralEmployee("小虎", 8, 7500, 0);
		
		employeeList.add(mep1);
		employeeList.add(mep2);
		employeeList.add(gep1);
		employeeList.add(gep2);
		employeeList.add(gep3);
		
		// 财务部 对公司员工的工资核算/访问
		FADepartment department = new FADepartment();
		for(Employee employee : employeeList){
			employee.accept(department);
		}	
	}
	
}

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

FADepartment department = new FADepartment();
修改为如下即可
HRDepartment department = new HRDepartment();
8.程序运行结果:

管理者: 王总  固定工资 =20000.0, 迟到时长 10小时, 实发工资=19950.0
管理者: 谢经理  固定工资 =15000.0, 迟到时长 15小时, 实发工资=14925.0
普通员工: 小杰  固定工资 =8000.0, 迟到时长 8小时, 实发工资=7920.0
普通员工: 小晓  固定工资 =8500.0, 迟到时长 12小时, 实发工资=8380.0
普通员工: 小虎  固定工资 =7500.0, 迟到时长 0小时, 实发工资=7500.0

六、其他

Java设计模式之访问者模式

本文属于23种设计模式系列,介绍访问者模式。
  • jason0539
  • jason0539
  • 2015年04月21日 07:48
  • 9339

JAVA设计模式十四--Visitor(访问者模式)

访问者模式(Visitor Pattern)是GoF提出的23种设计模式中的一种,属于行为模式。 据《大话设计模式》中说算是最复杂也是最难以理解的一种模式了。    定义(源于GoF《Design...
  • hfmbook
  • hfmbook
  • 2012年06月22日 10:20
  • 8954

浅谈JAVA设计模式之——访问者模式(Visitor)

一、概述 表示一个作用于某对象结构中的各元素的操作。 它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 二、适用性 1.一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实...
  • l1028386804
  • l1028386804
  • 2015年05月09日 14:27
  • 1081

Java设计模式(二十五):访问者模式

访问者模式(Visitor Pattern) 访问者模式(Visitor Pattern):属于类的行为模式。表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于...
  • longdan3105
  • longdan3105
  • 2018年01月25日 11:56
  • 22

Java设计模式之--访问者模式(Visitor)

概念: 访问者模式(Visitor)行为设计模式。访问者模式被用在针对一组相同类型对象的操作。优点是,可以把针对此对象的操作逻辑转移到另外一个类上。用于数据结构和作用于结构上的操作解耦合,使得操作集合...
  • lqh517
  • lqh517
  • 2016年06月24日 12:12
  • 336

java 访问者模式

原文出处:http://blog.csdn.net/zhengzhb/article/details/7489639   定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前...
  • chenhuade85
  • chenhuade85
  • 2012年11月02日 23:31
  • 3987

JAVA设计模式(23):行为型-访问者模式(Visitor)

想必大家都去过医院,虽然没有人喜欢去医院(爱岗敬业的医务工作人员除外,)。在医生开具处方单(药单)后,很多医院都存在如下处理流程:划价人员拿到处方单之后根据药品名称和数量计算总价,药房工作人员根据药品...
  • dreamsunday
  • dreamsunday
  • 2015年06月25日 10:40
  • 3660

java设计模式-访问者模式visit

一般场景:一个数据结构可以被多种不同对象访问操作; 类比:医院开的方子,可以被划价员计算医药费,可以被药房抓药,。。。 demo:  抽象访问者:Visitor.Java publ...
  • sidihuo
  • sidihuo
  • 2017年02月06日 14:11
  • 1154

《JAVA与模式》之访问者模式

在阎宏博士的《JAVA与模式》一书中开头是这样描述访问者(Visitor)模式的:   访问者模式是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的...
  • ystyaoshengting
  • ystyaoshengting
  • 2016年01月27日 16:51
  • 295

Java设计模式(三) Visitor(访问者)模式及多分派场景应用

基本概念Visitor 封装一些作用于数据结构中的各元素的操作,不同的操作可以借助新的visitor实现,降低了操作间的耦合性 访问者可以将数据结构和对数据的操作解耦,使得增加对数据结构的操作不需要取...
  • qq_24451605
  • qq_24451605
  • 2016年04月14日 15:32
  • 5208
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JAVA设计模式之 访问者模式【Visitor Pattern】
举报原因:
原因补充:

(最多只允许输入30个字)