访问者模式包含以下几个角色:java
●Vistor(抽象访问者):抽象访问者为对象结构中每个具体元素类ConcreteElement声明一个访问操做,从这个操做的名称或参数类型能够清楚知道须要访问的具体元素的类型,具体访问者须要实现这些操做方法,定义对这些元素的访问操做。 ●ConcreteVisitor(具体访问者):具体访问者实现了每一个由抽象访问者声明的操做,每个操做用于访问对象结构中一种类型的元素。 ●Element(抽象元素):抽象元素通常是抽象类或者接口,它定义一个accept()方法,该方法一般以一个抽象访问者做为参数。 ●ConcreteElement(具体元素):具体元素实现了accept()方法,在accept()方法中调用访问者的访问方法以便完成对一个元素的操做。 ●ObjectStructure(对象结构):对象结构是一个元素的集合,它用于存放元素对象,而且提供了遍历其内部元素的方法。它能够结合组合模式来实现,也能够是一个简单的集合对象,如一个List对象或一个Set对象
一、主要优势测试
(1) 增长新的访问操做很方便。使用访问者模式,增长新的访问操做就意味着增长一个新的具体访问者类,实现简单,无须修改源代码,符合“开闭原则”。 (2) 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构能够供多个不一样的访问者访问。 (3) 让用户可以在不修改现有元素类层次结构的状况下,定义做用于该层次结构的操做
二、主要缺点this
(1) 增长新的元素类很困难。在访问者模式中,每增长一个新的元素类都意味着要在抽象访问者角色中增长一个新的抽象操做,并在每个具体访问者类中增长相应的具体操做,这违背了“开闭原则”的要求。 (2) 破坏封装。访问者模式要求访问者对象访问并调用每个元素对象的操做,这意味着元素对象有时候必须暴露一些本身的内部操做和内部状态,不然没法供访问者访问
三、适用场景code
(1) 一个对象结构包含多个类型的对象,但愿对这些对象实施一些依赖其具体类型的操做。在访问者中针对每一种具体的类型都提供了一个访问操做,不一样类型的对象能够有不一样的访问操做。 (2) 须要对一个对象结构中的对象进行不少不一样的而且不相关的操做,而须要避免让这些操做“污染”这些对象的类,也不但愿在增长新操做时修改这些类。访问者模式使得咱们能够将相关的访问操做集中起来定义在访问者类中,对象结构能够被多个不一样的访问者类所使用,将对象自己与对象的访问操做分离。 (3) 对象结构中对象对应的类不多改变,但常常须要在此对象结构上定义新的操做
FinanceDepartment表示财务部,HRDepartment表示人力资源部,它们充当具体访问者的角色,其抽象父类Department充当抽象访问者角色;EmployeeList充当对象结构,用于存储员工列表;FullTimeEmployee表示全职员工,PartTimeEmployee表示兼职员工,它们充当具体元素角色,而其父类IEmployee(这里实现形式是interface)充当抽象元素角色。对象
/** * 2018/12/6 * 抽象元素类:Employee * * @author machuanpeng */ public interface IEmployee { void accept(Department handler); }
/** * 2018/12/6 * FullTimeEmployee * * @author machuanpeng */ public class FullTimeEmployee implements IEmployee { public string name; public double weeklyWage; public int workTime; public FullTimeEmployee(string name, double weeklyWage, int workTime){ this.name = name; this.weeklyWage = weeklyWage; this.workTime = workTime; } public void accept(Department handler){ handler.visit(this); } }
/** * 2018/12/6 * PartTimeEmployee * * @author machuanpeng */ public class PartTimeEmployee implements IEmployee { public string name; public double hourWage; public int workTime; public PartTimeEmployee(string name, double hourWage, int workTime){ this.name = name; this.hourWage = hourWage; this.workTime = workTime; } public void accept(Department handler){ handler.visit(this); } }
/** * 2018/12/6 * 对象结构类 * * @author machuanpeng */ public class EmployeeList { private List<IEmployee> empList = new ArrayList<IEmployee>(); public void addEmployee(IEmployee emp){ this.empList.add(emp); } public void accept(Department handler){ for(IEmployee emp : empList) { emp.accept(handler); } } }
/** * 2018/12/6 * 抽象访问者类 * * @author machuanpeng */ public abstract class Department { // 声明一组重载的访问方法,用于访问不一样类型的具体元素 public abstract void visit(FullTimeEmployee employee); public abstract void visit(PartTimeEmployee employee); }
/** * 2018/12/6 * FinanceDepartment * * @author machuanpeng */ public class FinanceDepartment extends Department { // 实现财务部对兼职员工数据的访问 public void visit(PartTimeEmployee employee){ String name = employee.name; int workTime = employee.workTime; double hourWage = employee.hourWage; System.out.println("临时工" + name+"实际工资为:"+workTime * hourWage+"元"); } // 实现财务部对全职员工数据的访问 public void visit(FullTimeEmployee employee) { String name = employee.name; int workTime = employee.workTime; double weekWage = employee.weeklyWage; if (workTime > 40) { weekWage = weekWage + (workTime - 40) * 50; } else if (workTime < 40) { weekWage = weekWage - (40 - workTime) * 80; if (weekWage < 0) { weekWage = 0; } } System.out.println("正式工" + name+"实际工资为:"+weekWage+"元"); } }
/** * 2018/12/6 * HRDepartment * * @author machuanpeng */ public class HRDepartment extends Department { // 实现人力资源部对兼职员工数据的访问 public void visit(PartTimeEmployee employee){ String name = employee.name; int workTime = employee.workTime; System.out.println("临时工" + name+"实际工做时间为:"+workTime+"小时"); } // 实现人力资源部对全职员工数据的访问 public void visit(FullTimeEmployee employee) { String name = employee.name; int workTime = employee.workTime; System.out.println("正式工" + name+"实际工做时间为:"+workTime+"小时"); if (workTime > 40) { int addTime = workTime-40; System.out.println("正式工" + name+"加班时间为:"+addTime+"小时"); } else if (workTime < 40) { int delTime = 40-workTime; System.out.println("正式工" + name+"请假时间为:"+delTime+"小时"); } } }
测试:blog
public class Client { public static void main(String args[]) { EmployeeList empList = new EmployeeList(); IEmployee fteA = new FullTimeEmployee("赵", 3200.00, 45); IEmployee fteB = new FullTimeEmployee("钱", 2000, 40); IEmployee fteC = new FullTimeEmployee("孙", 2400, 38); IEmployee fteD = new PartTimeEmployee("李", 80, 20); IEmployee fteE = new PartTimeEmployee("周", 60, 18); empList.addEmployee(fteA); empList.addEmployee(fteB); empList.addEmployee(fteC); empList.addEmployee(fteD); empList.addEmployee(fteE); Department dept = new FinanceDepartment(); empList.accept(dept); dept = new HRDepartment(); empList.accept(dept); } }