一、定义:分装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
通过给每个基础类设置一个访问者,通过访问者可以访问到基础类的数据结构,然后访问者对这些基础类的数据结构定义一些新的操作,而不改变基础类的数据结构。
二、简单代码示例
基础类1 负责销售兵乒球
public class Object1 {
private String name = "PingPongBall";
private int price = 10;
private static int stock = 100;
private static int income = 0;
public void sale(int num) {
if (stock < num) {
System.out.println("No enough stock");
return;
}
stock -= num;
income += num * price; //只有一个价格
}
public int reportIncome() {
System.out.println("The income of sale " + name + " is " + income);
return income;
}
public void accept(IVisitor visitor) { //设置访问者
visitor.visit(this);
}
}
基础类2 负责销售篮球public class Object2 {
private String name = "basketball";
private int outPrice = 100;
private static int stock = 100;
private static int inPrice = 50;
private static int income = 0;
public void sale(int num) {
if (stock < num) {
System.out.println("No enough stock");
return;
}
stock -= num;
income += num * (outPrice - inPrice); //分为进价 和销售价
}
public int reportIncome() {
System.out.println("The income of sale " + name + " is " + income);
return income;
}
public void accept(IVisitor visitor) { //设置访问者
visitor.visit(this);
}
}
访问者类:
public interface IVisitor { //设置访问者要访问的数据结构。 Object1 和 Object2 如果这两个对象是接口则更容易扩展
int visit(Object1 obj1);
int visit(Object2 obj2);
void report(); //在访问各种数据结构后,定义的新操作。
}
具体访问者
public class Visitor implements IVisitor {
private static int totalIncome = 0;
@Override
public int visit(Object1 obj1) { //访问Object1的数据结构,并做新的操作。
// TODO Auto-generated method stub
totalIncome += obj1.reportIncome();
return 0;
}
@Override
public int visit(Object2 obj2) { //访问Object2的数据结构,并做新的操作
// TODO Auto-generated method stub
totalIncome += obj2.reportIncome();
return 0;
}
@Override
public void report() { //向调用者报告自己重新整理得到的新数据结构,可以用来做报表
// TODO Auto-generated method stub
System.out.println("Our Company's income of this year is:" + totalIncome);
}
}
场景类:
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Object1 obj1 = new Object1();
Object2 obj2 = new Object2();
IVisitor visitor = new Visitor();
// 基础类负责销售
obj1.sale(2);
obj1.sale(4);
obj1.sale(10);
obj2.sale(50);
// 为每个基础类指定一个访问者,并通过访问者进行访问
obj1.accept(visitor);
obj2.accept(visitor);
// 通过访问者访问所有的类,并提取所需要的数据 向调用者报告
visitor.report();
}
}
The income of sale PingPongBall is 160
The income of sale basketball is 2500
Our Company's income of this year is:2660
三、
优点:访问者模式符合职责单一原则,基础类负责单一的职责,如果要做总的报表分析活动,则交给访问者类去处理。访问者怎么变化,并不影响基础类和场景,十分容易扩展。访问者对数据结构的处理十分灵活,可以做更多的操作。
缺点:访问者模式访问者去访问一个类,就要求该类暴漏一些方法和数据结构,违反迪米特法则。访问者依赖于具体类,违反了依赖倒置原则,不面向接口编程使得扩展有点困难。