最复杂的设计模式,并且使用频率不高,《设计模式》的作者评价为:大多情况下,你不需要使用访问者模式,但是一旦需要使用它时,那就真的需要使用了。
访问者模式是一种将数据操作和数据结构分离的设计模式。
例子:
年底,CEO和CTO开始评定员工一年的工作绩效,员工分为工程师和经理,CTO关注工程师的代码量、经理的新产品数量;CEO关注的是工程师的KPI和经理的KPI以及新产品数量。由于CEO和CTO对于不同员工的关注点是不一样的,这就需要对不同员工类型进行不同的处理。
员工基类
// 员工基类
public abstract class Staff {
public String name;
public int kpi;// 员工KPI
public Staff(String name) {
this.name = name;
kpi = new Random().nextInt(10);
}
// 核心方法,接受Visitor的访问
public abstract void accept(Visitor visitor);
}
工程师类
// 工程师
public class Engineer extends Staff {
public Engineer(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
// 工程师一年的代码数量
public int getCodeLines() {
return new Random().nextInt(10 * 10000);
}
}
经理类
// 经理
public class Manager extends Staff {
public Manager(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
// 一年做的产品数量
public int getProducts() {
return new Random().nextInt(10);
}
}
然后将这些员工添加到一个业务报表类中,公司高层可以通过该报表类的 showReport 方法查看所有员工的业绩
// 员工业务报表类
public class BusinessReport {
// 所有员工
private List<Staff> mStaffs = new LinkedList<>();
public BusinessReport() {
mStaffs.add(new Manager("经理-A"));
mStaffs.add(new Engineer("工程师-A"));
mStaffs.add(new Engineer("工程师-B"));
mStaffs.add(new Engineer("工程师-C"));
mStaffs.add(new Manager("经理-B"));
mStaffs.add(new Engineer("工程师-D"));
}
/**
* 为访问者展示报表
* @param visitor 公司高层,如CEO、CTO
*/
public void showReport(Visitor visitor) {
for (Staff staff : mStaffs) {
staff.accept(visitor);
}
}
}
定义一个Visitor接口
public interface Visitor {
// 访问工程师类型
void visit(Engineer engineer);
// 访问经理类型
void visit(Manager manager);
}
定义CEO类,(CEO只关注KPI,新产品数量)
// CEO访问者
public class CEOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("工程师: " + engineer.name + ", KPI: " + engineer.kpi);
}
@Override
public void visit(Manager manager) {
System.out.println("经理: " + manager.name + ", KPI: " + manager.kpi +
", 新产品数量: " + manager.getProducts());
}
}
再添加一个CTO类,(CTO 关注工程师代码行数,及经理的产品数量)
public class CTOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("工程师: " + engineer.name + ", 代码行数: " + engineer.getCodeLines());
}
@Override
public void visit(Manager manager) {
System.out.println("经理: " + manager.name + ", 产品数量: " + manager.getProducts());
}
}
最后Client用法:
public class Client {
public static void main(String[] args) {
// 构建报表
BusinessReport report = new BusinessReport();
System.out.println("=========== CEO看报表 ===========");
report.showReport(new CEOVisitor());
System.out.println("=========== CTO看报表 ===========");
report.showReport(new CTOVisitor());
}
}