2018.4.14 设计模式之访问者模式(通过例子结合说明)

某公司OA系统中包含一个员工信息管理子系统,该公司员工包括正式员工和临时工,每周人力资源部和财务部等部门需要对员工数据进行汇总,汇总数据包括员工工作时间、员工工资等。该公司基本制度如下:

(1) 正式员工每周工作时间为40小时,不同级别、不同部门的员工每周基本工资不同;如果超过40小时,超出部分按照100元/小时作为加班费;如果少于40小时,所缺时间按照请假处理,请假所扣工资以80元/小时计算,直到基本工资扣除到零为止。除了记录实际工作时间外,人力资源部需记录加班时长或请假时长,作为员工平时表现的一项依据。
(2) 临时工每周工作时间不固定,基本工资按小时计算,不同岗位的临时工小时工资不同。人力资源部只需记录实际工作时间。
人力资源部和财务部工作人员可以根据各自的需要对员工数据进行汇总处理,人力资源部负责汇总每周员工工作时间,而财务部负责计算每周员工工资。
现使用访问者模式设计该员工信息管理子系统。

具体实现过程

Client.java

package com.gult.demo10;

/**
 * 访问者模式   客户端 
 *  
 *  只要创建对象结构中的实例就行了
 * 
 * @author qichunlin
 *
 */
public class Client {
	public static void main(String[] args) {
		//创建员工的列表实例化   相当于我们平时写的管理类Manager
		EmployeeList list = new EmployeeList();

		//创建3个全职员工 创建2个兼职员工 对象
		Employee fte1,fte2,fte3,pte1,pte2;
		
		//通过构造方法把对象创建出来  并且赋值
		fte1 = new FulltimeEmployee("张无忌", 3200.00, 45);
		fte2 = new FulltimeEmployee("杨过", 2000.00, 40);
		fte3 = new FulltimeEmployee("段誉",2400.00,38);
		pte1 = new ParttimeEmployee("洪七公",80.00,20);
		pte2 = new ParttimeEmployee("郭靖",60.00,18);
		
		//将员工放进去集合中
		list.addEmployee(fte1);
		list.addEmployee(fte2);
		list.addEmployee(fte3);
		list.addEmployee(pte1);
		list.addEmployee(pte2);
		
                //调用XML文档
		Department dep = (Department)XMLUtil.getBean();
		list.accept(dep);
	}
}

Deparement.java

package com.gult.demo10;

/**
 * 部门类  抽象访问者类
 *  定义的方法和类用刀关键字   abstract   每一个抽象元素做一个声明访问的操作
 * 在具体访问类中的时候用的是继承方法
 * 有两种方法
 * @author qichunlin
 *
 */
public abstract class Department {
	//声明两个类型的工作   全职 兼职  的抽象方法
	public abstract void visit(FulltimeEmployee employee);
	public abstract void vist (ParttimeEmployee emplyee);
	

}

Employee.java

package com.gult.demo10;
**
 * 员工类  抽象元素类
 * 抽象元素用的是接口类  具体元素去实现这个抽象元素类
 * @author qichunlin
 *
 */
public interface Employee {
	//接受一个抽象访问者模式
	public void accept(Department handler);
}

EmployeeList.java

package com.gult.demo10;

import java.util.ArrayList;

/**
 * 员工列表类  对象结构
 * 
 * 提供高层接口,  允许访问者访问Element的子类,在该类中可以包含结构  
 * ArrayList  Vector 提供所要访问的element类的列表
 * 
 * @author qichunlin
 *
 */
public class EmployeeList {
        //创建Element元素集合 。 抽象元素
	private ArrayList<Employee> list = new ArrayList<Employee>();
	
	//增加员工
	public void addEmployee(Employee emplyee) {
		list.add(emplyee);
	}
	
	
	//遍历访问员工集合中的每一个员工对象
	public void accept(Department handler) {
		for(Object obj : list) {
			//这里需要转换类型不然访问不了里面的方法
			((Employee)obj).accept(handler);
			
		}
	}
}

FADepartment.java

package com.gult.demo10;

/**
 * 人力资源部    具体的访问类   继承部门的抽象访问类   包括实现里面的具体方法
 * 显示加班时间请假时间
 * @author qichunlin
 *
 */
public class FADepartment extends Department {

	// 实现财务部对  全职  的员工的访问
	@Override
	public void visit(FulltimeEmployee employee) {
		//获取员工的工作时间
		int workTime = employee.getWorkTime();
		//获取一周的工资
		double weekWage = employee.getWeeklyWage();
		if (workTime > 40) {
			weekWage = weekWage + (workTime - 40) * 100;
		} else if (workTime < 40) {
			weekWage = weekWage - (40 - workTime) * 80;

			if (weekWage < 0) {
				weekWage = 0;
			}

		}
		System.out.println("正式员工:"+employee.getName()+"	实际工资:"+weekWage+"元!!!");
	}
	
	
	//兼职的员工计算
	@Override
	public void vist(ParttimeEmployee emplyee) {
		int workTime = emplyee.getWorkTime();
		double hourWage = emplyee.getHourWage();
		System.out.println("临时工员工:"+emplyee.getName()+"工资是:"+hourWage * workTime+"元!!!");
		
	}

}

package com.gult.demo10;

/**
 * 全职员工类   具体元素类
 * 
 * @author qichunlin
 *
 */
public class FulltimeEmployee implements Employee{
	//姓名
	private String name;
	//周工资总额
	private double weeklyWage;
	//工作时间
	private int workTime;
	
	
	public FulltimeEmployee(String name, double weeklyWage, int workTime) {
		super();
		this.name = name;
		this.weeklyWage = weeklyWage;
		this.workTime = workTime;
	}

	public String getName() {
		return name;
	}

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

	public double getWeeklyWage() {
		return weeklyWage;
	}

	public void setWeeklyWage(double weeklyWage) {
		this.weeklyWage = weeklyWage;
	}

	public int getWorkTime() {
		return workTime;
	}

	public void setWorkTime(int workTime) {
		this.workTime = workTime;
	}

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

}

HRDepartment.java

package com.gult.demo10;

/**
 * 人力资源部  具体的访问类
 * 显示加班时间请假时间
 * @author qichunlin
 *
 */
public class HRDepartment extends Department{
	//实现人力资源对全部职工的访问
	@Override
	public void visit(FulltimeEmployee employee) {
		int workTime = employee.getWorkTime();
		System.out.println("正式员工:"+employee.getName() +"实际工作时间为:"+workTime+"小时");
		if(workTime >40) {
			System.out.println("正式员工:"+employee.getName()+"加班时间为:"+(workTime - 40)+"小时");
		}else if(workTime <40) {
			System.out.println("正式员工:"+employee.getName()+"请假时间为:"+(40 - workTime)+"小时");
		}
	}
	
	
	//对兼职员工的访问
	@Override
	public void vist(ParttimeEmployee emplyee) {
		int workTime = emplyee.getWorkTime();
		System.out.println("临时工:"+emplyee.getName()+"实际工作时间为:"+workTime+"小时");
	}

}

ParttimeEmployee.java

package com.gult.demo10;

/**
 * 兼职员工类 具体元素
 * 实现Employee类
 * @author qichunlin
 *
 */
public class ParttimeEmployee implements Employee{
	private String name;//名字
	private double hourWage;//小时工资
	private int workTime;//工作时间
	
	
	public String getName() {
		return name;
	}

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

	public double getHourWage() {
		return hourWage;
	}

	public void setHourWage(double hourWage) {
		this.hourWage = hourWage;
	}

	public int getWorkTime() {
		return workTime;
	}

	public void setWorkTime(int workTime) {
		this.workTime = workTime;
	}

	//有参构造方法
	public ParttimeEmployee(String name, double hourWage, int workTime) {
		super();
		this.name = name;
		this.hourWage = hourWage;
		this.workTime = workTime;
	}

	@Override
	public void accept(Department handler) {
		handler.vist(this);
	}

}

XMLUtil.java

package com.gult.demo10;
/**
 * XML文档的配置操作类
 * 
 * @author qichunlin
 *
 */
import javax.xml.parsers.*;  
import org.w3c.dom.*;  
import org.xml.sax.SAXException;  
import java.io.*;  

public class XMLUtil {
	
	//该方法用于从XML配置文件中提取具体类的类名,并返回一个实例对象
	public static Object getBean() {
		try {
			//创建文档对象
			DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder =  dFactory.newDocumentBuilder();
			Document doc;
                        doc = builder.parse(new File("/Users/qichunlin/eclipse-workspace/Mode/config.xml"));//苹果系统下要用这个路径
			
			//doc = builder.parse(new File("config.xml"));//这个是在同一个根目录下使用的
			
			
			//获取包含类名的文本节点
			NodeList n1 = doc.getElementsByTagName("className");
			Node classNode = n1.item(0).getFirstChild();
			String cName = classNode.getNodeValue();
			
			//通过类名生成实例对象并将其返回
			Class c = Class.forName(cName);
			Object obj = c.newInstance();
			return obj;
			
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

}

xml配置文档 config.xml

<?xml version="1.0"?>
<config>
	<className>com.gult.demo10.HRDepartment</className>
</config>

第二种简单

我们将创建一个定义接受操作的 ComputerPart 接口。Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart 接口的实体类。我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作。

VisitorPatternDemo,我们的演示类使用 Computer、ComputerPartVisitor 类来演示访问者模式的用法。

package com.glut.demo9;

public class Computer implements ComputerPart{
	ComputerPart[] parts;
	public Computer() {
		parts = new ComputerPart[] {new Mouse(),new Keyboard(),new Monitor()};
	}
	@Override
	public void accept(ComputerPartVisitor computerPartVisitor) {
		
		for (int i = 0; i < parts.length; i++) {
			parts[i].accept(computerPartVisitor);
		}
		
		computerPartVisitor.visit(this);
	}

}

package com.glut.demo9;

/**
 * 访问者模式
 * 
 * 定义表示元素的接口
 * 
 * @author qichunlin
 *
 */
public interface ComputerPart {
	public  void accept(ComputerPartVisitor computerPartVisitor);
}

package com.glut.demo9;

/**
 * 创建实现ComputerPartVisitor 的类
 * 
 * @author qichunlin
 *
 */
public class ComputerPartDisplayVisitor implements ComputerPartVisitor{

	@Override
	public void visit(Computer computer) {
		System.out.println("Displaying Computer");
	}

	@Override
	public void visit(Mouse mouse) {
		// TODO Auto-generated method stub
		System.out.println("Displaying Mouse");
	}

	@Override
	public void visit(Keyboard keyboard) {
		// TODO Auto-generated method stub
		System.out.println("Displaying Keyboard");
	}

	@Override
	public void visit(Monitor monitor) {
		// TODO Auto-generated method stub
		System.out.println("Displating Monitor");
	}

}

package com.glut.demo9;

/**
 * 定义一个表示访问者的接口
 * 
 * @author qichunlin
 *
 */
public interface ComputerPartVisitor {
	public void visit(Computer computer);
	public void visit(Mouse mouse);
	public void visit(Keyboard keyboard);
	public void visit(Monitor monitor);
	
}

package com.glut.demo9;

public class Keyboard implements ComputerPart{

	@Override
	public void accept(ComputerPartVisitor computerPartVisitor) {
		computerPartVisitor.visit(this);
	}

}

package com.glut.demo9;

public class Monitor implements ComputerPart{

	@Override
	public void accept(ComputerPartVisitor computerPartVisitor) {
		// TODO Auto-generated method stub
		computerPartVisitor.visit(this);
	}

}

package com.glut.demo9;

public class Mouse implements ComputerPart{

	@Override
	public void accept(ComputerPartVisitor computerPartVisitor) {
		computerPartVisitor.visit(this);
	}

}

package com.glut.demo9;

/**
 * 使用ComputerPartDisplayVistor 来显示Computer的组成部分
 * 
 * @author qichunlin
 *
 */
public class Test {
	public static void main(String[] args) {
		Computer computer = new Computer();
		computer.accept(new ComputerPartDisplayVisitor());
	}
}

原文地址:https://www.cnblogs.com/qichunlin/p/8820688.html