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

设计模式,学习,十九,访问者,模式 · 浏览次数 : 61

小编点评

**访问者模式** 访问者模式是一种行为型模式,它在结构不变的情况下动态改变对于内部元素的动作。 **设计模式学习中的应用** 访问者模式在以下场景中使用: * **可复用性:**不同的访问器实现同样的访问操作,可以根据不同的需求选择不同的访问策略。 * **可维护性:**通过创建不同的访问器,可以简化对组件的维护。 * **可扩展性:**访问器可以轻松扩展以支持新的访问策略。 **示例** 假设我们需要构造一台电脑,有主板( Board ),CPU ,内存( Memory ),但是针对企业用户和个人用户,电脑组件的价格是不一样的。我们可以使用访问者模式构建以下访问器接口和实现类: **抽象访问器接口:** ```java public interface Visitor { void visitCPU(CPU cpu); void visitBoard(Board board); void visitMemory(Memory memory); } ``` **具体访问器实现类:** ```java 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; } } 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; } } ``` **使用访问者模式的代码:** ```java // 创建访问器 Visitor visitor = new CorpVisitor(); // 向主板、内存和 CPU 传递访问操作 CPU cpu = new CPU(); Memory memory = new Memory(); Board board = new Board(); cpu.accept(visitor); memory.accept(visitor); board.accept(visitor); // 获取访问器的价格 System.out.println("访问器价格:" + visitor.getTotalPrice()); ``` **结论** 访问者模式是一种强大的设计模式,可以有效地构建可复用、可维护、可扩展的软件系统。

正文

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

作者: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 <a href="mailto:410486047@qq.com">GreyZeng</a>
 * @version 1.0, 2022/8/11
 */
public class FileVisitorTest {
    public static void main(String[] args) throws IOException {
        // 使用FileVisitor对目录进行遍历
        // 访问当前目录的所有文件
        Files.walkFileTree(Paths.get("."), new SimpleFileVisitor<Path>() {

            // 在访问子目录前触发该方法
            @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 图

代码

更多

设计模式学习专栏

参考资料

与设计模式学习(十九):访问者模式相似的内容:

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

设计模式学习(十九):访问者模式 作者:Grey 原文地址: 博客园:设计模式学习(十九):访问者模式 CSDN:设计模式学习(十九):访问者模式 访问者模式 访问者模式是一种行为型模式。 访问者模式在结构不变的情况下动态改变对于内部元素的动作。 举例说明: 假设我们需要构造一台电脑,有主板( Bo

设计模式学习(十):门面模式

设计模式学习(十):门面模式 作者:Grey 原文地址: 博客园:设计模式学习(十):门面模式 CSDN:设计模式学习(十):门面模式 门面模式 门面模式是一种结构型模式。 门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。 假设建造一个房子需要有如下三个步骤: 第一步,和泥 第二

设计模式学习(十一):组合模式

设计模式学习(十一):组合模式 作者:Grey 原文地址: 博客园:设计模式学习(十一):组合模式 CSDN:设计模式学习(十一):组合模式 组合模式 组合模式是一种结构型模式。 组合模式中,最常用的一个用法就是目录层级的遍历,话不多说,直接上代码,主方法中 public class Main {

设计模式学习(十二):享元模式

设计模式学习(十二):享元模式 作者:Grey 原文地址: 博客园:设计模式学习(十二):享元模式 CSDN:设计模式学习(十二):享元模式 享元模式 享元模式是一种结构型模式。 一个应用场景是:运用共享技术有效地支持大量细粒度的对象。主要解决 在有大量对象时,有可能会造成内存溢出,我们把其中共同的

设计模式学习(十三):观察者模式

设计模式学习(十三):观察者模式 作者:Grey 原文地址: 博客园:设计模式学习(十三):观察者模式 CSDN:设计模式学习(十三):观察者模式 观察者模式 观察者模式是一种行为型模式。在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。 一般可以用做事件处理

设计模式学习(十四):模板方法

设计模式学习(十四):模板方法 作者:Grey 原文地址: 博客园:设计模式学习(十四):模板方法 CSDN:设计模式学习(十四):模板方法 模板方法 模板方法是一种行为型模式。 假设我们要实现一个游戏,这个游戏有「初始化」,「启动」,「结束」三个方法,那么可以定义一个游戏的模板: public a

设计模式学习(十五):策略模式

设计模式学习(十五):策略模式 作者:Grey 原文地址: 博客园:设计模式学习(十五):策略模式 CSDN:设计模式学习(十五):策略模式 策略模式 策略模式是一种行为型模式,它定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。 以实例来说明 假设我们有一个猫类,这个类里面有体重和身高

设计模式学习(十六):责任链模式

设计模式学习(十六):责任链模式 作者:Grey 原文地址: 博客园:设计模式学习(十六):责任链模式 CSDN:设计模式学习(十六):责任链模式 责任链模式 责任链模式是一种行为型模式。 举例说明:有一段文本需要过滤一系列敏感字,我们可以通过责任链模式来设计这个功能,假设文本是 scripts H

设计模式学习(十七):状态模式

设计模式学习(十七):状态模式 作者:Grey 原文地址: 博客园:设计模式学习(十七):状态模式 CSDN:设计模式学习(十七):状态模式 状态模式 状态模式是一种行为型模式。 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。 举例说明: Person 有 Cry ,

设计模式学习(十八):迭代器模式

设计模式学习(十八):迭代器模式 作者:Grey 原文地址: 博客园:设计模式学习(十八):迭代器模式 CSDN:设计模式学习(十八):迭代器模式 迭代器模式 迭代器模式是一种行为型模式。 迭代器最典型的应用是容器遍历 模仿 JDK 的容器,我们自定义一个容器并实现 iterator 方法; 首先,