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

访问者模式是一种行为型设计模式,允许在不修改对象结构的情况下,为对象的元素添加新的操作。示例展示了如何使用访问者模式计算不同客户类型下电脑组件的价格,如公司用户和个人用户的价格策略。此外,还提到了Java中的FileVisitor作为访问者模式的实际应用,并提供了相关代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

作者: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 图如下

img

访问者模式的应用

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 图

代码

更多

设计模式学习专栏

参考资料

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GreyZeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值