访问者模式属于一种行为型设计模式,其核心思想是:针对某个对象结构中的各个元素,定义新的操作方式,而无需修改这些元素本身的类。这种模式能够在不改变原有元素类的情况下,为它们动态地添加新功能。
举个例子来说明:假设一个图书馆系统管理着两种文献类型——图书和论文。现在需要统计所有馆藏文献的总页数。如果有一本555页的图书和两篇各49页的论文,则总页数为604页。这个“统计页数”的操作就是一个新增的操作行为。在这个场景中,图书和论文是对象结构(即图书馆管理系统)中的两个不同元素,通过访问者模式,可以为这两个元素统一添加“被统计页数”的能力。
/**
* 抽象访问者类
*/
public interface Person{
// 操作狗
void operate(Dog dog);
// 操作猫
void operate(Cat cat);
}
/**
* 具体访问类(主人)
*/
public class Owner implements Person{
@Override
public void operate(Dog dog) {
System.out.println("主人给狗狗喂食...");
}
@Override
public void operate(Cat cat) {
System.out.println("主人给狗狗喂食...");
}
}
/**
* 具体访问类(其他人)
*/
public class Other implements Person{
@Override
public void operate(Dog dog) {
System.out.println("其他人给狗狗喂食了...");
}
@Override
public void operate(Cat cat) {
System.out.println("其他人给猫猫喂食了...");
}
}
/**
* 抽象元素类(动物类)
*/
public interface Animal {
// 提供给访问者访问的方法
void execute(Person person);
}
/**
* 具体元素类(猫)
*/
public class Cat implements Animal{
@Override
public void execute(Person person) {
person.operate(this);
System.out.println("猫猫被喂食了,喵喵喵...");
}
}
/**
* 具体元素类(狗)
*/
public class Dog implements Animal{
@Override
public void execute(Person person) {
person.operate(this);
System.out.println("小狗狗被喂食了,汪汪汪...");
}
}
/**
* 结构对象角色(家)
*/
public class Home {
// 聚合所有元素类
private List<Animal> list = new ArrayList<>();
public void addAnimal(Animal animal){
list.add(animal);
}
// 对所有元素类访问
public void operateAll(Person person){
for (Animal animal : list) {
animal.execute(person);
}
}
}
public class Client {
public static void main(String[] args) {
Home home = new Home();
home.addAnimal(new Cat());
home.addAnimal(new Dog());
home.operateAll(new Owner());
}
}
访问者模式的核心角色
1. 抽象访问者角色:负责声明对每一个元素类型进行访问的方法,每个方法对应一种元素类型。通常情况下,方法的数量与元素类的数量一致,且将对应的元素作为参数传入。需要注意的是,该模式要求元素类的种类保持不变。
2. 具体访问者角色:实现抽象访问者中定义的具体行为,明确当访问某一类元素时应执行的操作逻辑。
3. 抽象元素角色:定义一个接受访问者的方法接口(如 accept 方法),表明该元素可以被访问者访问。
4. 具体元素角色:实现抽象元素中的接收方法,通常在实现中调用访问者的访问方法,并将自身作为参数传递过去,从而完成双向连接。
5. 对象结构角色:表示包含多个元素的结构体,它具备容器特性或复合对象特征,能够存储一组元素并支持遍历操作,以便让访问者依次访问其中的每一个元素。
访问者模式的优势与局限性
优点:
- 良好的扩展性:可以在不改动元素类的前提下,为其增加新的操作功能,符合开放封闭原则中的“对扩展开放”。
- 提升复用性:通过定义通用的访问者逻辑,可在多个场景下重复使用同一套操作流程,增强代码复用程度。
- 职责分离清晰:将不同的、无关的操作行为分别封装到独立的访问者中,使得每个访问者只关注特定的功能,提高了模块化程度。
缺点:
- 难以应对结构变动:每当对象结构中新增一个元素类时,所有具体访问者都必须相应地添加处理该元素的方法,这违背了“开闭原则”中的“对修改关闭”原则。
- 违反依赖倒置原则:访问者往往直接依赖于具体的元素类,而不是抽象接口,导致系统耦合度上升,灵活性降低。
适用的应用场景
访问者模式适用于以下情况:
- 对象结构相对稳定,但对其执行的操作算法频繁变化。
- 需要对对象结构中的元素实施多种差异较大且互不关联的操作,同时希望避免这些操作的变化影响到对象本身的结构设计。
实际案例解析
以宠物喂养为例进行说明:在家庭环境中,宠物可以由主人或其他人进行喂食。
在此场景中:
- 抽象访问者角色:代表“喂食者”,是一个人的抽象类,定义喂食行为。
- 具体访问者角色:包括“主人”和“其他人”,分别实现各自的喂食逻辑。
- 抽象元素角色:动物的抽象类,定义可被访问的基本结构。
- 具体元素角色:如“宠物狗”和“宠物猫”,实现接受访问者的具体方法。
- 对象结构角色:指“主人家里”,作为容纳各种宠物的对象结构,提供统一的访问入口。


雷达卡


京公网安备 11010802022788号







