设计模式之访问者模式

目录

定义

访问者模式(Visitor Pattern)是一种‌行为型设计模式‌,其核心思想是将数据结构与数据操作解耦,允许在不修改现有对象结构的前提下定义作用于对象元素的新操作。

访问者模式有以下核心要点:

1)‌数据结构稳定,被访问的对象结构(元素类)相对固定,不频繁变动。

2)‌操作可扩展,新增操作只需添加新的访问者类,无需修改元素类代码,符合开闭原则。

3)‌双分派机制,通过accept(Visitor)和visit(Element)的两次动态绑定,根据元素类型调用对应操作。

结构

适用场景

访问者模式适用于以下场景:

1)‌对象结构稳定但需频繁新增操作,如编译器语法树分析(类型检查、代码优化等操作)。

2)‌避免元素类被污染,当元素类不宜直接包含某些操作时(如电商商品类不宜包含打折、导出等业务逻辑)。

3)‌统一处理复合结构,对集合、树形结构中的异构元素执行统一操作(如文档导出、统计计算)。

使用示例

电商订单价格计算。假设订单包含不同类型商品(普通商品/折扣商品),需支持多种计算规则(含税价计算、满减计算)。

定义抽象Element

复制代码
/**
 * 定义商品元素接口(抽象Element角色)
 */
public interface OrderItem {

    void accept(PriceVisitor visitor);

    double getBasePrice(); // 所有商品必须提供基础价格

}

定义具体Element

复制代码
/**
 * 具体商品类(普通商品)
 */
public class RegularItem implements OrderItem {

    private String name;

    private double price;

    public RegularItem(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public void accept(PriceVisitor visitor) {
        visitor.visit(this); // 关键:将自身作为参数传递
    }

    @Override
    public double getBasePrice() {
        return price;
    }

    // 普通商品特有方法
    public String getName() {
        return name;
    }

}

/**
 * 具体商品类(折扣商品)
 */
public class DiscountItem implements OrderItem {

    private String name;

    private double price;

    private double discountRate; // 折扣率

    public DiscountItem(String name, double price, double discountRate) {
        this.name = name;
        this.price = price;
        this.discountRate = discountRate;
    }

    @Override
    public void accept(PriceVisitor visitor) {
        visitor.visit(this); // 关键:将自身作为参数传递
    }

    @Override
    public double getBasePrice() {
        return price * discountRate;
    }

    // 折扣商品特有方法
    public double getDiscountRate() {
        return discountRate;
    }

    public String getName() {
        return name;
    }
}

定义抽象Visitor

复制代码
/**
 * 访问者接口(抽象Visitor角色)
 */
public interface PriceVisitor {

    void visit(RegularItem item);

    void visit(DiscountItem item);

}

定义具体Visitor

复制代码
/**
 * 具体访问者:满减计算
 */
public class PromotionVisitor implements PriceVisitor {

    private final double threshold; // 满减阈值

    private final double reduction; // 减免金额

    public PromotionVisitor(double threshold, double reduction) {
        this.threshold = threshold;
        this.reduction = reduction;
    }

    @Override
    public void visit(RegularItem item) {
        double finalPrice = item.getBasePrice();
        if (finalPrice >= threshold) {
            finalPrice -= reduction;
            System.out.printf("普通商品[%s] 满减后价格: %.2f\n",
                    item.getName(), finalPrice);
        }
    }

    @Override
    public void visit(DiscountItem item) {
        // 折扣商品不参与满减
        System.out.println("折扣商品[" + item.getName() + "]不参与满减活动");
    }

}

/**
 * 具体访问者:含税价格计算
 */
public class TaxPriceVisitor implements PriceVisitor {

    private double totalTax = 0;

    private final double taxRate;

    public TaxPriceVisitor(double taxRate) {
        this.taxRate = taxRate;
    }

    @Override
    public void visit(RegularItem item) {
        double tax = item.getBasePrice() * taxRate;
        totalTax += tax;
        System.out.printf("普通商品[%s] 含税价: %.2f (税额: %.2f)\n",
                item.getName(), item.getBasePrice() + tax, tax);
    }

    @Override
    public void visit(DiscountItem item) {
        double tax = item.getBasePrice() * taxRate * 0.5; // 折扣商品税额减半
        totalTax += tax;
        System.out.printf("折扣商品[%s]含税价: %.2f (折扣率: %.1f, 税额: %.2f)\n",item.getName(),
                item.getBasePrice() + tax, item.getDiscountRate(), tax);
    }

    public double getTotalTax() {
        return totalTax;
    }

}

定义ObjectStructure角色

复制代码
/**
 * 对象结构(订单)(ObjectStructure角色)
 */
public class Order {

    private List<OrderItem> items = new ArrayList<>();

    public void addItem(OrderItem item) {
        items.add(item);
    }

    public void accept(PriceVisitor visitor) {
        for (OrderItem item : items) {
            item.accept(visitor); // 触发双分派
        }
    }
}

测试

复制代码
public class Client {

    public static void main(String[] args) {
        Order order = new Order();
        order.addItem(new RegularItem("iPhone", 5999));
        order.addItem(new DiscountItem("运动鞋", 399, 0.8));

        // 计算含税价
        TaxPriceVisitor taxVisitor = new TaxPriceVisitor(0.13);
        order.accept(taxVisitor);
        System.out.println("总税额: " + taxVisitor.getTotalTax());

        // 计算满减
        PromotionVisitor promoVisitor = new PromotionVisitor(5000, 300);
        order.accept(promoVisitor);
    }
}
相关推荐
我命由我123452 小时前
Kotlin 数据容器 - List(List 概述、创建 List、List 核心特性、List 元素访问、List 遍历)
java·开发语言·jvm·windows·java-ee·kotlin·list
武子康4 小时前
Java-80 深入浅出 RPC Dubbo 动态服务降级:从雪崩防护到配置中心秒级生效
java·分布式·后端·spring·微服务·rpc·dubbo
YuTaoShao7 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
源码_V_saaskw7 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
超浪的晨7 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
双力臂4048 小时前
Spring Boot 单元测试进阶:JUnit5 + Mock测试与切片测试实战及覆盖率报告生成
java·spring boot·后端·单元测试
Edingbrugh.南空8 小时前
Aerospike与Redis深度对比:从架构到性能的全方位解析
java·开发语言·spring
QQ_4376643149 小时前
C++11 右值引用 Lambda 表达式
java·开发语言·c++
永卿0019 小时前
设计模式-迭代器模式
java·设计模式·迭代器模式
使二颗心免于哀伤9 小时前
《设计模式之禅》笔记摘录 - 10.装饰模式
笔记·设计模式