访问者模式(Visitor Pattern)
半塘 2024/3/29 Java进阶
将数据操作与数据结构分离,将一些稳定的对象的类拥有一个accept方法用来接收访问者访问。
# 1、访问者模式案例
- 年终时,公司高层会根据每个员工这一年做出的功劳发年终奖,对基层员工和对管理层员工发的奖金也是不一样。
- 设计思路:为了简单模拟这个过程,我们把员工分为工程师和经理,公司高层分为CTO和CEO。CTO只关注代码行数和代码质量,CEO只关注业绩。
定义一个接受访问者的方法accept(Visitor v)方法。此类作为抽象元素类。
public abstract class Staff {
public String name;
public int kpi;
public Staff(String name){
this.name = name;
this.kpi = new Random().nextInt(10);
}
public abstract void accept(Vistor vistor);
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
比较稳定的数据结构,稳定的对象的类拥有一个accept方法用来接收访问者访问。
// 经理
public class Manager extends Staff {
private int products; //产品数量
public Manager(String name) {
super(name);
products = new Random().nextInt(10);
}
@Override
public void accept(Vistor vistor) {
vistor.vist(this);
}
public int getProducts() {
return products;
}
}
// 工程师
public class Engineer extends Staff {
private int codeLines; // 代码行数
public Engineer(String name) {
super(name);
codeLines = new Random().nextInt(10 * 10000);
}
@Override
public void accept(Vistor vistor) {
vistor.vist(this);
}
public int getCodeLines(){
return codeLines;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
抽象访问者类
public interface Vistor {
void vist(Engineer engineer);
void vist(Manager manager);
}
1
2
3
4
2
3
4
具体的访问者
// CEO访问者
public class CEOVistor implements Vistor {
@Override
public void vist(Engineer engineer) {
System.out.println("工程师:" + engineer.name + ",KPI:" + engineer.kpi);
}
@Override
public void vist(Manager manager) {
System.out.println("经理:" + manager.name + ",KPI:" + manager.kpi
+ ",新产品数量:" + manager.getProducts());
}
}
// CTO访问者
public class CTOVistor implements Vistor {
@Override
public void vist(Engineer engineer) {
System.out.println("工程师:" + engineer.name + ",代码数量:" + engineer.getCodeLines());
}
@Override
public void vist(Manager manager) {
System.out.println("经理:" + manager.name + ",产品数量:" + manager.getProducts());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
将访问者和元素做一个关联。
public class BusinessReport {
List<Staff> mStaffs = new ArrayList<>();
public BusinessReport(){
mStaffs.add(new Manager("王经理"));
mStaffs.add(new Manager("陈经理"));
mStaffs.add(new Engineer("Android开发者"));
mStaffs.add(new Engineer("iOS开发者"));
mStaffs.add(new Engineer("php开发者"));
}
public void showReport(Vistor vistor){
for (Staff staff : mStaffs){
staff.accept(vistor);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
测试
public class ClientTest {
public static void main(String[] args) {
//构建报表
BusinessReport businessReport = new BusinessReport();
System.out.println("====给CEO看的报表====");
businessReport.showReport(new CEOVistor());
System.out.println("====给CTO看的报表====");
businessReport.showReport(new CTOVistor());
}
}
/**
* 输出结果:
* ====给CEO看的报表====
* 经理:王经理,KPI:3,新产品数量:4
* 经理:陈经理,KPI:8,新产品数量:5
* 工程师:Android开发者,KPI:3
* 工程师:iOS开发者,KPI:0
* 工程师:php开发者,KPI:7
* ====给CTO看的报表====
* 经理:王经理,产品数量:4
* 经理:陈经理,产品数量:5
* 工程师:Android开发者,代码数量:20545
* 工程师:iOS开发者,代码数量:60319
* 工程师:php开发者,代码数量:91292
* /
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
参考:https://www.cnblogs.com/twcat/p/16912767.html