Technology-设计模式-访问者模式

本文介绍了GoF中的访问者模式。

模式推演

应节涨价的商品

情人节来了,花鱼店的老板要对商品进行涨价,其中,鱼涨价两倍,花涨价三倍,但是过完节后,商品又必须回复原价,所以,老板不想修改商品本身的价格。

初始设计如下:

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
37
38
39
40

interface getValentineDayPrice {
public int getValentineDayPrice();
}

class Fish implements getValentineDayPrice {

private int price;

public Fish(){
price = 10;
}

public int getPrice(){
return price;
}

@Override
public int getValentineDayPrice(){
return price * 2;
}
}

class Flower implements getValentineDayPrice {

private int price;

public Flower(){
price = 5;
}

public int getPrice(){
return price;
}

@Override
public int getValentineDayPrice(){
return price * 3;
}
}

这种做法弊端很明显,当我需要修改涨价的倍数时,需要修改类本身,而且,情人节过后,也得修改类移除getValentineDayPrice接口。

封装变化

变化的部分是价格,我们希望可以修改价格,又不修改类本身,因此,我们将价格变化的部分用一个独立的类来负责,称为访问者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface Visitor {
public int visit(Fish fish);
public int visit(Flower flower);
}

class CountVisitor implements Visitor {

@Override
public int visit(Fish fish) {
return fish.getPrice() * 2;
}

@Override
public int visit(Flower flower) {
return flower.getPrice() * 3;
}

}

这样做的好处是,不需要修改原先的类,即使引入新的商品,也只需要增加一个方法即可,当要回复原价的时候,也只需要修改访问者类即可。

接受访问

由于访问者需要获取Fish以及Flower的属性,所以我们设计一个被访问者接口,用于接收访问者:

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
37
38
39
interface Visitable {
public void accept(Visitor visitor);
}

class Fish implements Visitable {

private int price;

public Fish(){
price = 10;
}

@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}

public int getPrice(){
return price;
}
}

class Flower implements Visitable {

private int price;

public Flower(){
price = 5;
}

@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}

public int getPrice(){
return price;
}
}

调用

对于花鱼店的老板,也就是这个设计的用户而言,只需要调用访问者即可获取商品的价格。

1
2
3
4
5
6
7
8
9
10
11
public class Main {

public static void main(String[] args) {
CountVisitor visitor = new CountVisitor();
int totalCount = 0;
totalCount += visitor.visit(new Fish());
totalCount += visitor.visit(new Flower());
System.out.println("TotalCount:" + totalCount);
}

}

结果:

1
TotalCount:35

定义

访问者模式(Visitor Pattern):当想要为一个对象的组合添加新的能力,且封装并不重要时使用。

类图:

Technology-DesignPattern-Visitor-Class

用途:

  • 为对象的组合添加新的能力。

优点:

  • 允许对组合结构加入新的操作,而无需改变结构本身;
  • 想要加入新的操作,相对容易;
  • 访问者所进行的操作,其代码是集中在一起的。

缺点:

  • 当采用访问者模式时,就打破了组合类的封装;
  • 因为游走的功能牵涉其中,所以对组合结构的改变就更加困难。