3.11设计模式——Visitor 访问者模式(行为型)

意图

表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。

结构

  • Visitor(访问者)为该对象结构中ConcreteElement(具体元素)的每一个类声明一个Visit操作,该操作的名字和特征标识了发送Visit请求给该访问者的那个类,这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
  • ConcreteVisitor(具体访问者)实现每个有Visitor声明的操作,每个操作实现本算法的一部分,而算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累计结果。
  • Element(元素)定义以一个访问者为参数的Accept操作。
  • ConcreteElement(具体元素)实现以一个访问者为参数的Accept操作。
  • ObjectStructure(对象结构)能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个组合或者是一个集合,如一个列表或一个无序集合。

适用性

  • 一个对象结构包含很多类对象,它们有不同的接口,而用户想对这些对象实施一些依赖于具体类的操作。
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而又想要避免这些操作污染这些对象的类,Visitor使得用户可以将相关的操作集中起来定义再一个类中。当该对象结构被很多应用共享是,用Visitor模式让每个应用仅包含需要用到的操作。
  • 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对独有访问者的接口,这可能需要很大的代价。如果对象结构经常改变,那么可能还是在这些类中定义这些操作较好。

代码示例

java 复制代码
// Element接口
interface Element {
    void accept(Visitor visitor);
}

// ConcreteElement具体元素类
class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visitConcreteElementA(this);
    }
}

class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visitConcreteElementB(this);
    }
}

// Visitor访问者接口
interface Visitor {
    void visitConcreteElementA(ConcreteElementA element);
    void visitConcreteElementB(ConcreteElementB element);
}

// ConcreteVisitor具体访问者类
class ConcreteVisitor implements Visitor {
    @Override
    public void visitConcreteElementA(ConcreteElementA element) {
        System.out.println("访问者正在访问 ConcreteElementA");
    }

    @Override
    public void visitConcreteElementB(ConcreteElementB element) {
        System.out.println("访问者正在访问 ConcreteElementB");
    }
}

// ObjectStructure对象结构类
class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void addElement(Element element) {
        elements.add(element);
    }

    public void removeElement(Element element) {
        elements.remove(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

// 示例用法
public class VisitorPatternExample {
    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.addElement(new ConcreteElementA());
        objectStructure.addElement(new ConcreteElementB());

        Visitor visitor = new ConcreteVisitor();
        objectStructure.accept(visitor);
    }
}
  1. Element(元素)接口定义了一个接受访问者的方法 accept(Visitor visitor),该方法允许访问者访问元素。

  2. ConcreteElementA 和 ConcreteElementB 是具体元素类,它们实现了 Element 接口,并在 accept 方法中调用访问者的相应方法,将自身作为参数传递给访问者。

  3. Visitor(访问者)接口声明了访问具体元素的方法,例如 visitConcreteElementAvisitConcreteElementB

  4. ConcreteVisitor(具体访问者)类实现了 Visitor 接口,提供了对具体元素的访问方法的具体实现。

  5. ObjectStructure(对象结构)类维护了一个元素列表,并提供了一个接受访问者的方法 accept,在该方法中遍历元素列表,调用每个元素的 accept 方法,让访问者访问每个元素。

相关推荐
咖啡八杯26 分钟前
GoF设计模式——中介者模式
java·后端·spring·设计模式
青石路4 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
像我这样帅的人丶你还7 小时前
Java 后端详解(五):Redis 缓存
java·后端·全栈
plainGeekDev9 小时前
GreenDAO → Room
android·java·kotlin
胡萝卜术14 小时前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
亦暖筑序14 小时前
Java 8老系统AI Workflow实战:把一次性AI对话升级成可恢复工作流
java·后端
敲代码的彭于晏15 小时前
Bean 生命周期完全图解:前端同学也能看懂的 Spring 核心机制
java·前端·后端
plainGeekDev16 小时前
ButterKnife → ViewBinding
android·java·kotlin
像我这样帅的人丶你还1 天前
Java 后端详解(四):分页与搜索
java·javascript·后端
她的男孩1 天前
数据权限为什么不能只靠注解?Forge 的 Mapper 层 SQL 改写源码拆解
java·后端·架构