介绍:封装一些作用域某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
场景:平时在进行绩效考核的时候,CEO和CTO进行比较的东西是不同的。比如CEO只关心业绩,而CTO关心代码质量,项目成果。如果将考核写成一个方法进行维护,会有大量的逻辑判断,代码不美观且难以维护。
适用:
- 一个对象结构包含很多类对象,它们有不同接口,而需要对这些对象实施一些依赖于其具体类的操作。
- 需对一个对象结构中的对象进行很多不同且不相关的操作,但需要避免这些操作“污染”这些对象的类。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
一、角色及作用
角色 | 作用 |
---|---|
Vistor | 抽象访问者。为该对象结构中的ConcreteElement的每一个类声明的一个操作。 |
ConcreteVisitor | 具体访问者。实现Visitor申明的每一个操作,每一个操作实现算法的一部分。 |
Element | 抽象元素。定义一个Accept操作,它以一个访问者为参数。 |
ConcreteElement | 具体元素 。实现Accept操作。 |
ObjectStructure | 对象结构。能够枚举它的元素,可以提供一个高层的接口来允许访问者访问它的元素。 |
二、苦逼的员工们
介绍:员工们就是参与考核的人。他们给供访问者查看内部属性的方法。
员工基类
public abstract class Staff {
public String name;
public int 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);
}
}
三、大BOSS和报表
介绍:访问者需要实现对各种类型提供不同的访问方式,报表则是将员工信息录入。
访问者
public interface Visitor {
// 访问工程师类型
public void visit(Engineer engineer);
// 访问经理类型
public void visit(Manager manager);
}
CEO只关心KPI
public class CEO 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);
}
}
CTO关心工作成绩
public class CTO 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());
}
}
员工业绩报表
public class BusinessReport {
List<Staff> staffs = new ArrayList<Staff>();
public BusinessReport() {
staffs.add(new Manager("李经理"));
staffs.add(new Manager("陈经理"));
staffs.add(new Engineer("java-李四"));
staffs.add(new Engineer("python-张安"));
staffs.add(new Engineer("C++-赵伟"));
}
/**
* 展示业绩报表
*/
public void showReport(Visitor visitor) {
for (Staff staff : staffs) {
staff.accept(visitor);
}
}
}
四、开始考核
// 构建报表
BusinessReport report = new BusinessReport();
System.out.println("=====CEO======");
report.showReport(new CEO());
System.out.println("=====CTO======");
report.showReport(new CTO());
输出
=====CEO======
经理:李经理,KPI:5
经理:陈经理,KPI:3
工程师:java-李四,KPI:9
工程师:python-张安,KPI:2
工程师:C++-赵伟,KPI:3
=====CTO======
经理:李经理,产品量:2
经理:陈经理,产品量:1
工程师:java-李四,代码量:95904
工程师:python-张安,代码量:46538
工程师:C++-赵伟,代码量:53854
总结:将一堆业务判断都分离了,代码层面十分简洁。不足也是会增加类的数量。
更多模式:一天一个设计模式—分类与六大原则