元月's blog 元月's blog
首页
  • 基础
  • 并发编程
  • JVM
  • Spring
  • Redis篇
  • Nginx篇
  • Kafka篇
  • Otter篇
  • Shardingsphere篇
  • 设计模式
  • MySQL
  • Oracle
  • 基础
  • 操作系统
  • 网络
  • 数据结构
  • 技术文档
  • Git常用命令
  • GitHub技巧
  • 博客搭建
  • 开发工具
更多

元月

临渊羡鱼,不如退而结网
首页
  • 基础
  • 并发编程
  • JVM
  • Spring
  • Redis篇
  • Nginx篇
  • Kafka篇
  • Otter篇
  • Shardingsphere篇
  • 设计模式
  • MySQL
  • Oracle
  • 基础
  • 操作系统
  • 网络
  • 数据结构
  • 技术文档
  • Git常用命令
  • GitHub技巧
  • 博客搭建
  • 开发工具
更多
  • 设计模式

    • 设计模式简介
    • 设计模式之单例模式
    • 设计模式之工厂模式
    • 设计模式之原型模式
    • 设计模式之建造者模式
    • 设计模式之适配器模式
    • 设计模式之桥接模式
    • 设计模式之组合模式
    • 设计模式之装饰器模式
    • 设计模式之外观模式
    • 设计模式之享元模式
    • 设计模式之代理模式
    • 设计模式之责任链模式
    • 设计模式之命令模式
    • 设计模式之解释器模式
    • 设计模式之迭代器模式
    • 设计模式之中介者模式
    • 设计模式之备忘录模式
    • 设计模式之观察者模式
    • 设计模式之状态模式
    • 设计模式之策略模式
    • 设计模式之模版模式
    • 设计模式之访问者模式
      • 一、简介
      • 二、实现方式
      • 三、应用场景
        • 1、访问者模式在 ASM 框架中的使用
        • 2、访问者模式在 JDK 文件树遍历的使用
      • 四、思维导图
    • 设计模式辨析篇
  • 高可用

  • 系统设计
  • 设计模式
元月
2022-08-20
目录

设计模式之访问者模式

# 设计模式之访问者模式

# 一、简介

将数据的结构与数据的操作行为分离,即:把不变的固定起来,变化的开放出去

# 二、实现方式

  • 抽象访问者(Visitor): 访问者的抽象类或接口,定义了访问者的行为

    public interface Visitor {
        public void askSchoolExperience(String name);
        public void askWorkExperience(String name);
        public void askScienceAchievement(String name);
    }
    
    1
    2
    3
    4
    5
  • 具体访问者(ConcreteVisitor): 实现了Visitor

    public class XinhuaVisitor implements Visitor{
        @Override
        public void askSchoolExperience(String name) {
            System.out.printf("请问%s:在学校取得的最大成就是什么?\n", name);
        }
        @Override
        public void askWorkExperience(String name) {
            System.out.printf("请问%s:工作上最难忘的事情是什么?\n", name);
        }
        @Override
        public void askScienceAchievement(String name) {
            System.out.printf("请问%s:最大的科研成果是什么?", name);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • ObjectStructure:能枚举它的元素,可以提供一个高层的接口,用来允许访问者访问元素

  • 抽象元素(Element):定义一个accept方法,用来接收一个访问者对象

  • 具体元素(ConcreteElement):实现了Element,重写了accept方法

    public class Scientist {
        private Visitor visitor;
        private String name;
        private Scientist(){}
        public Scientist(String name) {
            this.name = name;
        }
        public void accept(Visitor visitor) {
            this.visitor = visitor;
        }
        public void interview(){
            System.out.println("------------访问开始------------");
            System.out.println("---开始聊学校经历---");
            visitor.askSchoolExperience(name);
            System.out.println("---开始聊工作经历---");
            visitor.askWorkExperience(name);
            System.out.println("---开始聊科研成果---");
            visitor.askScienceAchievement(name);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
  • 测试类

    public class Client {
        public static void main(String[] args) {
            Scientist yang = new Scientist("杨振宁");
            yang.accept(new XinhuaVisitor());
            yang.interview();
        }
    }
    ------------访问开始------------
    ---开始聊学校经历---
    请问杨振宁:在学校取得的最大成就是什么?
    ---开始聊工作经历---
    请问杨振宁:工作上最难忘的意见事情是什么?
    ---开始聊科研成果---
    请问杨振宁:最大的科研成果是什么?
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

# 三、应用场景

对象结构相对稳定,但其操作算法经常变化的场景

# 1、访问者模式在 ASM 框架中的使用

ASM 是 Java 的字节码增强技术,可以用来对字节码进行修改。在 ASM 中和访问者模式相关的三个类是:ClassVisitor、ClassWriter、ClassReader

  • ClassVisitor 是一个抽象类,定义了访问者的行为。相当于抽象访问者

  • ClassWriter 实现了ClassVisitor,相当于具体访问者

    它负责将修改后的字节码输出为字节数组

    public final void visitSource(String var1, String var2) {
            if (var1 != null) {
                this.sourceFile = this.newUTF8(var1);
            }
    
            if (var2 != null) {
                this.sourceDebug = (new ByteVector()).encodeUTF8(var2, 0, 2147483647);
            }
    
        }
    
        public final void visitOuterClass(String var1, String var2, String var3) {
            this.enclosingMethodOwner = this.newClass(var1);
            if (var2 != null && var3 != null) {
                this.enclosingMethod = this.newNameType(var2, var3);
            }
    
        }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
  • ClassReader类的 accept ()方法,传入了一个 ClassVisitor 对象。相当于具体元素

    它负责将字节数组或 class 文件读入内存中,并以树的数据结构表示

public void accept(ClassVisitor var1, Attribute[] var2, int var3) {
        
        ...
        ...

        var1.visit(this.readInt(this.items[1] - 7), var7, var8, var28, var9, var10);
        if ((var3 & 2) == 0 && (var12 != null || var13 != null)) {
            var1.visitSource(var12, var13);
        }

        if (var14 != null) {
            var1.visitOuterClass(var14, var15, var16);
        }

        int var29;
        if (var17 != 0) {
            var23 = this.readUnsignedShort(var17);

            for(var29 = var17 + 2; var23 > 0; --var23) {
                var29 = this.readAnnotationValues(var29 + 2, var5, true, var1.visitAnnotation(this.readUTF8(var29, var5), true));
            }
        }

        ...
        ...

        var1.visitEnd();
    }
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

# 2、访问者模式在 JDK 文件树遍历的使用

假如说我们现在需要实现这样一个功能,循环打印出文件和文件夹的名称,又或者统计文件和文件夹的大小。

在这里,不变的是文件的遍历操作,变化的是打印文件名称和统计文件大小的操作。

  • JDK 中声明了一个 FileVisitor接口,定义了遍历者可以做的操作,相当于抽象访问者

    FileVisitor 中定义的 visitFile () 方法,其实就是对于文件的访问。被访问者(文件)的信息通过第一个参数 file 传递过来。这样遍历者就可以访问文件的内容了

  • SimpleFileVisitor 实现了 FileVisitor接口,相当于具体访问者

  • JDK 中的 Files 类,相当于具体元素`

    Files 类中的 walkFileTree ()方法实现了文件树的遍历,通过 FileVisitor 类的 visitFile() 等方法将遍历到的文件传递给遍历者,从而达到分离变化的目的

# 四、思维导图

#设计模式
设计模式之模版模式
设计模式辨析篇

← 设计模式之模版模式 设计模式辨析篇→

最近更新
01
otter二次开发-支持按目标端主键索引Load数据
08-03
02
mvnw简介
06-21
03
gor流量复制工具
06-03
更多文章>
Theme by Vdoing | Copyright © 2022-2024 元月 | 粤ICP备2022071877号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式