设计模式源码git地址:design-pattern-src: 设计模式源码 (gitee.com)

这个模式比较抽象,用到了双分派技术,比较复杂

  1. 定义
  2. 使用场景
  3. 角色
  4. 场景举例
  5. 总结

定义

封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于其内部各个元素的新操作

使用场景

类结构比较稳定,不会经常增删不同类型的元素。而需要经常给这些元素添加新的操作的时候,考虑使用此设计模式。(元素不变,操作变)

角色

ObjectStructure

封装元素用的结构,可以操作或访问之中的元素

Visitor

访问者,接口,定义元素的方法

ConcreteVisitor

访问者实现类

Element

结构中的元素

ConcreteElement

元素实现类

场景举例

王老板开了家公司,招了小李,小雷。打算疯狂压榨打工人。要求做前端,后端,测试,部署,产品销售等等,而且近期不准备招新人。

这种就符合元素不变(就一个人)而操作经常变(一会儿干这,一会儿干那的)

下面进行实现

这么一家有爱的公司,就叫它有爱公司

是这么调用的

1
2
3
4
5
6
//创建有爱公司
LoveCompany loveCompany = new LoveCompany();
//制作产品
loveCompany.build(new BuildProject());
//销售产品
loveCompany.build(new SaleProject());

类图

img

打工人抽象

1
2
3
4
public interface Worker {
//干活
void accept(Visitor visitor);
}

小李倒霉蛋

1
2
3
4
5
6
public class Lee implements Worker {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

小雷倒霉蛋

1
2
3
4
5
6
public class Ray implements Worker {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

访问者(将来干什么活),一个人(元素)对应一个方法

1
2
3
4
public interface Visitor {
void visit(Lee lee);
void visit(Ray ray);
}

有爱公司

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LoveCompany {
private List<Worker> employee= new ArrayList<>();

public LoveCompany() {
employee.add(new Lee());
employee.add(new Ray());
}

public void build(Visitor visitor){
for (Worker slave : employee) {
slave.accept(visitor);
}
}
}

现在王老板要求开发出一套产品来,让小李干设计前端,小雷干后端测试

1
2
3
4
5
6
7
8
9
10
11
public class BuildProject implements Visitor {
@Override
public void visit(Lee lee) {
System.out.println("悲催的小李进行设计,前端开发");
}

@Override
public void visit(Ray ray) {
System.out.println("悲催的小雷进行后端开发,测试工作");
}
}

王老板觉得干得不错,小伙子们有前途,给我销售吧,小李营销,小雷帮公司记账

1
2
3
4
5
6
7
8
9
10
11
public class BuildProject implements Visitor {
@Override
public void visit(Lee lee) {
System.out.println("悲催的小李进行设计,前端开发");
}

@Override
public void visit(Ray ray) {
System.out.println("悲催的小雷进行后端开发,测试工作");
}
}

改日,王老板觉得小伙子们做的不错,表示他家房子还蛮大的,晚上来开party。。

结果输出

1
2
3
4
悲催的小李进行设计,前端开发
悲催的小雷进行后端开发,测试工作
小李开始卖力营销,争做奋斗好青年
小雷开始帮公司做账,早日做大做强

总结

1、可以看出,有爱公司可以识别出干活场景(根据不同的打工人),如果在加一个小蔡(元素),改动会比较大这个模式就不适用了

2、如果继续给他们安排活,只需要增加一个类,符合开闭原则

3、这里出现了双分派的技术

所以来解释一下,更多的可以去网上和实战中了解

1
2
3
4
5
public void build(Visitor visitor){
for (Worker slave : employee) {
slave.accept(visitor);
}
}

会根据不同的打工人来调用各自的行为,在运行期决定,所以也叫动态单分派。

点进去看各自元素的实现

1
2
3
4
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}

visitor方法由传入的this决定,如果this为小李就执行小李的方法,小雷就是小雷的方法,所以又是一个动态单分派

和前一次一起算就是伪动态双分派,为什么是伪的?Java是一个单分派语言,这里是通过分别的两次加起来才实现双分派,所以是伪的