• 设计模式学习(十九):访问者模式


    设计模式学习(十九):访问者模式

    作者:Grey

    原文地址:

    博客园:设计模式学习(十九):访问者模式

    CSDN:设计模式学习(十九):访问者模式

    访问者模式#

    访问者模式是一种行为型模式。

    访问者模式在结构不变的情况下动态改变对于内部元素的动作。

    举例说明:

    假设我们需要构造一台电脑,有主板( Board ),CPU ,内存( Memory ),但是针对企业用户和个人用户,电脑组件的价格是不一样的,我们需要根据不同客户获取一台电脑的总价格。

    我们先抽象出电脑组件这个类

    public abstract class ComputerPart {
        abstract void accept(Visitor visitor);
    
        abstract int getPrice();
    }
    

    每个具体组件会继承这个抽象类,以主板( Board )为例

    public class Board extends ComputerPart {
        @Override
        void accept(Visitor visitor) {
            visitor.visitBoard(this);
        }
    
        @Override
        int getPrice() {
            return 20;
        }
    }
    

    抽象出一个访问者( Visitor )接口,

    public interface Visitor {
        void visitCPU(CPU cpu);
    
        void visitBoard(Board board);
    
        void visitMemory(Memory memory);
    }
    

    每个具体类型的访问者实现这个接口,然后定义其不同的价格策略,以公司访问者为例( CorpVisitor )

    public class CorpVisitor implements Visitor {
        private int totalPrice;
    
        @Override
        public void visitCPU(CPU cpu) {
            totalPrice += cpu.getPrice() - 1;
        }
    
        @Override
        public void visitBoard(Board board) {
            totalPrice += board.getPrice() - 2;
        }
    
        @Override
        public void visitMemory(Memory memory) {
            totalPrice += memory.getPrice() - 3;
        }
    
        public int getTotalPrice() {
            return totalPrice;
        }
    }
    

    个人访问者( PersonalVisitor )类似

    
    public class PersonalVisitor implements Visitor {
        private int totalPrice;
    
        @Override
        public void visitCPU(CPU cpu) {
            totalPrice += cpu.getPrice() + 1;
        }
    
        @Override
        public void visitBoard(Board board) {
            totalPrice += board.getPrice() + 2;
        }
    
        @Override
        public void visitMemory(Memory memory) {
            totalPrice += memory.getPrice() + 3;
        }
    
    
        public int getTotalPrice() {
            return totalPrice;
        }
    }
    
    

    主方法调用方式如下

    public class Main {
        public static void main(String[] args) {
            ComputerPart cpu = new CPU();
            ComputerPart memory = new Memory();
            ComputerPart board = new Board();
            PersonalVisitor personalVisitor = new PersonalVisitor();
            cpu.accept(personalVisitor);
            memory.accept(personalVisitor);
            board.accept(personalVisitor);
            System.out.println(personalVisitor.getTotalPrice());
    
            ComputerPart cpu2 = new CPU();
            ComputerPart memory2 = new Memory();
            ComputerPart board2 = new Board();
            CorpVisitor corpVisitor = new CorpVisitor();
            cpu2.accept(corpVisitor);
            memory2.accept(corpVisitor);
            board2.accept(corpVisitor);
            System.out.println(corpVisitor.getTotalPrice());
        }
    }
    

    可以看到,不同的访问者,对于电脑的价格是不一样的。

    上述示例的 UML 图如下

    image

    访问者模式的应用

    Java SE 中的 FileVisitor 使用了访问者模式,使用示例

    import java.io.IOException;
    import java.nio.file.FileVisitResult;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.nio.file.SimpleFileVisitor;
    import java.nio.file.attribute.BasicFileAttributes;
    
    /**
     * @author GreyZeng
     * @version 1.0, 2022/8/11
     */
    public class FileVisitorTest {
        public static void main(String[] args) throws IOException {
            // 使用FileVisitor对目录进行遍历
            // 访问当前目录的所有文件
            Files.walkFileTree(Paths.get("."), new SimpleFileVisitor() {
    
                // 在访问子目录前触发该方法
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    System.out.println("正在访问" + dir + "目录");
                    return FileVisitResult.CONTINUE;
                }
    
                // 在访问文件时触发该方法
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    System.out.println("正在访问" + file + "文件");
                    return FileVisitResult.CONTINUE;
                }
    
                // 在访问失败时触发该方法
                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                    // 写一些具体的业务逻辑
                    return super.visitFileFailed(file, exc);
                }
    
                // 在访问目录之后触发该方法
                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    // 写一些具体的业务逻辑
                    return super.postVisitDirectory(dir, exc);
                }
            });
        }
    }
    

    其他应用

    • 做编译器的时候,需要生成 AST ,进行类型检查 根据抽象语法树,生成中间代码;

    • XML 文件解析;

    • Spring 中的 BeanDefinitionVisitor

    UML 和 代码#

    UML 图

    代码

    更多#

    设计模式学习专栏

    参考资料#

  • 相关阅读:
    【Mediator模式】C++设计模式——中介者模式
    天然产物在新冠中的应用潜力 | MedChemExpress
    Julia绘图初步:Plots
    【力扣周赛】第 367 场周赛(⭐二维数组当成一维数组,前后缀分解)
    资深博导:我以为数据预处理是常识,直到遇到自己的学生
    一个线程的生命周期有哪几种状态?它们之间如何流转的?
    vue2视频video循环渲染卡顿
    学习笔记-SQLi
    线性代数的本质(一)——向量空间
    php案例:今天是星期几呢?
  • 原文地址:https://www.cnblogs.com/greyzeng/p/16883994.html