设计模式之 访问者模式

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不改变类的前提下,增加新的操作。换句话说,访问者模式使得你能够定义一个新的操作,作用于一个包含不同对象的对象结构上,而无需修改这些对象的类。该模式通过将操作封装在访问者类中,分离了算法与数据结构的结合,使得代码更加灵活和扩展性更强。

访问者模式的核心思想是"通过一个访问者对象对一组对象(元素)进行操作,避免了直接修改这些对象的类。"

一、访问者模式的结构

访问者模式的结构主要由以下几个角色组成:

  1. Visitor(访问者接口):定义所有的访问方法,每个方法对应一个元素类的操作。
  2. ConcreteVisitor(具体访问者):实现访问者接口,定义对每个元素类的具体操作。
  3. Element(元素接口):定义接受访问者的方法。元素类通过该方法来接受访问者的访问。
  4. ConcreteElement(具体元素):实现元素接口,定义一个具体的元素类,可以是集合、树形结构等。
  5. ObjectStructure(对象结构):通常是一个元素的集合,提供一个方法来遍历所有的元素,并将当前元素传递给访问者。
二、访问者模式的工作原理

访问者模式通过将访问者与元素解耦合,从而使得在不修改元素类的情况下可以添加新的操作。访问者模式通过以下几个步骤来实现:

  1. 创建访问者接口(Visitor):访问者接口定义了针对每个具体元素类的访问方法。
  2. 创建具体访问者(ConcreteVisitor):实现访问者接口,提供对每个具体元素的操作。
  3. 创建元素接口(Element) :每个元素类实现此接口,定义接受访问者的 accept() 方法,通常在该方法中调用访问者的访问方法。
  4. 创建具体元素类(ConcreteElement):具体元素类实现元素接口,并定义与访问者的交互逻辑。
  5. 创建对象结构(ObjectStructure):对象结构是一个包含多个元素的集合,可以通过该结构遍历并访问所有元素。

当一个访问者对象访问某个元素时,元素会调用访问者的相应方法,从而使得访问者能够对元素执行某些操作。

三、示例代码

以下是一个简单的访问者模式示例,展示了如何通过访问者模式对一组不同的元素执行操作。

访问者接口
java 复制代码
public interface Visitor {
    void visitDog(Dog dog);

    void visitCat(Cat cat);
}
元素接口
java 复制代码
public interface Animal {
    void accept(Visitor visitor);
}
具体元素类
java 复制代码
public class Dog implements Animal{
    private String name;

    public Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitDog(this);
    }
}
java 复制代码
public class Cat implements Animal{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Cat(String name) {
        this.name = name;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitCat(this);
    }
}
具体访问者类
java 复制代码
public class FoodRequirementVisitor implements Visitor{
    @Override
    public void visitDog(Dog dog) {
        System.out.println(dog.getName()+"需要吃饭");
    }

    @Override
    public void visitCat(Cat cat) {
        System.out.println(cat.getName()+"需要吃饭");
    }
}
java 复制代码
public class WaterRequirementVisitor implements Visitor{

    @Override
    public void visitDog(Dog dog) {
        System.out.println(dog.getName()+"需要喝水");
    }

    @Override
    public void visitCat(Cat cat) {
        System.out.println(cat.getName()+"需要喝水");
    }
}
对象结构
java 复制代码
public class Home {
    private List<Animal> list = new ArrayList<>();
    public void addAnimal(Animal animal){
        list.add(animal);
    }

    public void showAnimals(Visitor visitor){
        for (Animal animal : list) {
            animal.accept(visitor);
        }
    }
}
客户端
java 复制代码
public class Client {
    public static void main(String[] args) {
        Cat cat = new Cat("小白");
        Dog dog = new Dog("小黑");
        Home home = new Home();
        home.addAnimal(cat);
        home.addAnimal(dog);

        home.showAnimals(new FoodRequirementVisitor());
        home.showAnimals(new WaterRequirementVisitor());

    }
}
输出结果
四、访问者模式的优缺点
优点:
  1. 可以在不修改元素类的情况下,增加新的操作:访问者模式可以在不改变元素类代码的情况下,增加新的操作或行为,这样可以避免污染原有类的结构,提高了代码的灵活性和可扩展性。
  2. 符合单一职责原则:每个访问者类只负责一个特定的操作,操作与元素的定义是分离的,因此符合单一职责原则。
  3. 简化元素类:元素类不需要定义复杂的操作,操作都由访问者来完成,因此元素类通常会变得更简单。
缺点:
  1. 增加了类的数量:由于每增加一个新的操作,就需要创建一个新的访问者类,这可能会导致类的数量急剧增加,特别是当有很多元素类和操作时。
  2. 元素类需要改变:虽然访问者模式能够在不修改操作的情况下扩展新的操作,但如果有新的元素类加入,所有的访问者类都需要修改,意味着访问者模式并不能完全避免对元素类的修改。
  3. 对元素的结构要求较高 :访问者模式需要将元素的 accept() 方法与访问者的 visit() 方法对接,因此在设计时需要非常谨慎。
五、应用场景

访问者模式通常适用于以下场景:

  1. 需要对一组对象进行操作:当一组不同类型的对象需要执行一系列操作,而这些操作很少变动时,访问者模式非常适用。操作可以由访问者进行封装和实现,从而避免修改这些对象的代码。
  2. 需要定义多个操作,但不想改变元素类:如果需要对对象结构进行多次不同的操作,而且这些操作会随着时间变化,访问者模式提供了一种不修改元素类的方式来增加新的操作。
  3. 复杂的对象结构:当对象结构较为复杂,并且操作多样时,使用访问者模式可以将操作与数据结构分离,从而使得扩展和修改变得更加容易。
相关推荐
Jelena157795857928 小时前
电商运营分析数据比价接口实战:多平台价格监控与智能决策系统
java·大数据·数据库
神明不懂浪漫9 小时前
【第五章】Java中的继承与多态
java·开发语言
葬送的代码人生11 小时前
别再让 AI 瞎写代码了!Vibe Coding 三步法教你写出靠谱代码
前端·设计模式·架构
AI多Agent协作实战派11 小时前
AI多Agent协作系统实战(十七):凌晨4点,我的AI系统在“假装工作“——3个bug同时爆炸的5小时
java·前端·bug
gaolei_eit11 小时前
Java+Ai+vue
java·spring·maven
qq_25183645711 小时前
基于java Web 动漫视频网站毕业论文
java·开发语言·前端
LayZhangStrive11 小时前
JUC相关的函数、注解、变量杂记
java·面试·多线程·juc
未秃头的程序猿11 小时前
给公司做了个AI客服Agent,用的Spring AI 1.0,3天上线领导拍板了
java·后端·ai编程
曹牧11 小时前
Eclipse 批量文本替换
java·ide·eclipse
程序员清风12 小时前
OpenAI官方发布最新提示词技巧!
java·后端·面试