Java访问者模式(Visitor Pattern)是一种行为型设计模式,它允许将算法与其所操作的对象分离.该模式定义了一个访问者对象,它可以访问不同类型的对象并执行一些操作,同时也能让你在不修改现有代码的情况下,添加新的操作.
再访问者模式中,有两个重要的角色:访问者和元素. 元素是一个对象结构的组成部分.访问者是一个表示要执行的操作的对象.访问者可以通过元素的接受方法来访问元素.
Java访问者模式通常涉及以下5种角色:
- 抽象访问者(Visitor):定义了可以访问每个元素的访问方法.
- 具体访问者(Concrete Visitor):实现了抽象访问者定义的访问方法,包含针对不同元素的具体操作.
- 抽象元素(Element):定义了一个接受访问者对象的方法,使访问者可以访问自己.
- 具体元素(Concrete Element):实现了抽象元素定义的接受访问者方法,使访问者能够访问自己.
- 对象结构(Object Structure):包含元素的集合,可以提供迭代器遍历元素,并且可以接受访问者的访问.
实现
动物园中有不同种类的动物,包括狗,猫和鸟.访问者模式可以用于统计不同类型的动物的个数,以及不同类型的动物的属性信息.
抽象元素
1
2
3
|
public interface Animal {
void accept(Visitor visitor);
}
|
具体元素
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
|
@Data
public class Bird implements Animal{
private String name;
private String habitat;
public Bird(String name, String habitat) {
this.name = name;
this.habitat = habitat;
}
@Override
public void accept(Visitor visitor) {
visitor.visitor(this);
}
}
@Data
public class Cat implements Animal{
private String sound;
private int age;
public Cat(String sound, int age) {
this.sound = sound;
this.age = age;
}
@Override
public void accept(Visitor visitor) {
visitor.visitor(this);
}
}
@Data
public class Dog implements Animal{
private String color;
private int size;
public Dog(String color, int size) {
this.color = color;
this.size = size;
}
@Override
public void accept(Visitor visitor) {
visitor.visitor(this);
}
}
|
抽象访问者
1
2
3
4
5
|
public interface Visitor {
void visitor(Dog dog);
void visitor(Cat cat);
void visitor(Bird bird);
}
|
具体访问者
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
41
42
43
|
public class AnimalCountVisitor implements Visitor{
private int dogCount;
private int birdCount;
private int catCount;
@Override
public void visitor(Dog dog) {
dogCount++;
}
@Override
public void visitor(Cat cat) {
catCount++;
}
@Override
public void visitor(Bird bird) {
birdCount++;
}
public void printCount(){
System.out.println("狗的个数:"+dogCount);
System.out.println("猫的个数:"+catCount);
System.out.println("鸟的个数:"+birdCount);
}
}
public class AnimalFeatureVisitor implements Visitor {
private List<String> features;
public AnimalFeatureVisitor() {
features = new ArrayList<>();
}
@Override
public void visitor(Dog dog) {
features.add("Dog:color=" + dog.getColor() + ",size=" + dog.getSize());
}
@Override
public void visitor(Cat cat) {
features.add("Car:sound=" + cat.getSound() + ",age=" + cat.getAge());
}
@Override
public void visitor(Bird bird) {
features.add("Bird:name=" + bird.getName() + ",habitat=" + bird.getHabitat());
}
public void printFeatures(){
features.forEach(System.out::println);
}
}
|
测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class Demo {
public static void main(String[] args) {
List<Animal> animals = new ArrayList<>();
animals.add(new Dog("褐色", 50));
animals.add(new Dog("白色", 45));
animals.add(new Cat("喵喵叫", 2));
animals.add(new Cat("呜呜声", 3));
animals.add(new Bird("鹦鹉", "森林"));
animals.add(new Bird("麻雀", "田野"));
AnimalCountVisitor animalCountVisitor = new AnimalCountVisitor();
AnimalFeatureVisitor animalFeatureVisitor = new AnimalFeatureVisitor();
animals.forEach(animal -> {
animal.accept(animalCountVisitor);
animal.accept(animalFeatureVisitor);
});
animalCountVisitor.printCount();
animalFeatureVisitor.printFeatures();
}
}
|
再这个例子中,我们定义了三种动物类,包括Dog,Cat和Bird,它们都实现了Animal接口,并且是心啊了accept方法,其中传入了Visitor类型的参数.
接下来,定义了Visitor接口,其中包含了visitor方法,该方法根据传入的不同类型的动物进行访问.
再具体的Visitor的实现中,定义了AnimalCountVisitor和AnimalFeatureVisitor两个访问者,前者用于统计不同类型的动物的个数,后者用于打印不同类型的动物的属性.
总结
优点
- 分离算法与对象:访问者模式使得算法与对象分离成为可能,因为算法被定义在访问者中,而对象则在被访问时向访问者公开自己的数据.
- 扩展性好:该模式可以方便地添加新的操作而不会影响现有的对象结构,因为访问者模式将对象结构与操作分离开来.
- 符合开闭原则:访问者模式符合开闭原则,因为您可以在不更改现有代码的情况下添加新的访问者和新的元素类型.
- 简化代码逻辑:访问者模式将对象和操作分离开来,简化了代码逻辑.
缺点
- 增加新的元素类型困难:当需要增加新的元素类型时,必须修改现有的访问者接口,这可能导致对现有代码的修改.
- 破坏封装:访问者模式需要将对象的内部数据暴漏给访问者,这可能破坏对象的封装性.
应用场景
- 当需要对一个复杂对象结构进行操作而不想暴漏其内部实现时,可以使用访问者模式.
- 当需要为对象结构中的各个对象增加一些新的操作而不影响其类层次结构时,可以使用访问者模式.
- 当对象的类层次结构发生变化,但其操作仍然保持相对稳定时,可以使用访问者模式.
- 当需要在运行时动态确定要执行的操作时,可以使用访问者模式.
|