likes
comments
collection
share

设计模式Java实现-访问者模式

作者站长头像
站长
· 阅读数 46

✨这里是第七人格的博客✨小七,欢迎您的到来~✨

🍅系列专栏:设计模式🍅

✈️本篇内容: 访问者模式✈️

🍱 本篇收录完整代码地址:gitee.com/diqirenge/d… 🍱

楔子

有时候小七在想,技术真的有那么重要吗?

举个例子,如果不走内推,以小七现在的年龄和学历,毫不夸张的说,根本不会有面试的机会,简历直接就过不了。但是转而一想,也正是自己不断的自我提升,才会换来朋友们的信任与内推,所以一定要学会投资自己。

需求背景

假设我们有一个电子商务系统,其中包含了不同类型的商品,如书籍、电子产品等。每种商品都有一些共同属性和特有属性。现在,我们需要对不同类型的商品进行不同的操作,比如打印商品信息、计算商品的价格等。

分析设计

为了实现这些功能,我们可以考虑使用访问者模式,因为它允许我们在不修改商品类的情况下增加新的操作。

UML图

根据分析设计,我们可以先画一个简单的UML图,后面通过UML图编码

设计模式Java实现-访问者模式

模块名称

visitor

模块地址

gitee.com/diqirenge/d…

模块描述

访问者模式代码示例

代码实现

1、定义商品接口

/**
 * 商品接口,定义了接受访问者的方法
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2024/06/25
 */
interface Product {
    /**
     * 接受一个访问者对象,以便访问者可以操作该商品
     * @param visitor
     */
    void accept(ProductVisitor visitor);
}

2、定义访问者接口

/**
 * 访问者接口,定义了访问不同类型商品的方法
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2024/06/25
 */
interface ProductVisitor {
    /**
     * 访问书籍的方法
     * @param book
     */
    void visitBook(Book book);

    /**
     * 访问电子产品的方法
     * @param device
     */
    void visitElectronicDevice(ElectronicDevice device);
}

3、实现书籍类

/**
 * 书籍类,实现了Product接口
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2024/06/25
 */
public class Book implements Product {
    /**
     * 书籍的标题
     */
    private String title;
    /**
     * 书籍的作者
     */
    private String author;
    /**
     * 书籍的价格
     */
    private double price;

    /**
     * 书籍的构造函数,用于初始化书籍的信息
     * @param title
     * @param author
     * @param price
     */
    public Book(String title, String author, double price) {  
        this.title = title;  
        this.author = author;  
        this.price = price;  
    }

    /**
     * 实现Product接口的accept方法,用于接受访问者
     * @param visitor
     */
    @Override  
    public void accept(ProductVisitor visitor) {
        // 调用访问者的visitBook方法,传入当前书籍对象
        visitor.visitBook(this);
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

4、实现电子产品类

/**
 * 电子产品类,实现了Product接口
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2024/06/25
 */
class ElectronicDevice implements Product {
    /**
     * 电子产品的型号
     */
    private String model;
    /**
     * 电子产品的品牌
     */
    private String brand;
    /**
     * 电子产品的价格
     */
    private double price;

    /**
     * 电子产品的构造函数,用于初始化电子产品的信息
     * @param model
     * @param brand
     * @param price
     */
    public ElectronicDevice(String model, String brand, double price) {  
        this.model = model;  
        this.brand = brand;  
        this.price = price;  
    }

    /**
     * 实现Product接口的accept方法,用于接受访问者
     * @param visitor
     */
    @Override  
    public void accept(ProductVisitor visitor) {
        // 调用访问者的visitElectronicDevice方法,传入当前电子产品对象
        visitor.visitElectronicDevice(this);
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

5、实现计算价格行为的访问者

/**
 * 计算价格访问者类,实现了ProductVisitor接口
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2024/06/25
 */
class CalculatePriceVisitor implements ProductVisitor {  
    private double totalPrice = 0; // 用于累计总价格  
  
    // 实现访问书籍的方法,累加书籍的价格到总价格中  
    @Override  
    public void visitBook(Book book) {  
        totalPrice += book.getPrice();  
    }  
  
    // 实现访问电子产品的方法,累加电子产品的价格到总价格中  
    @Override  
    public void visitElectronicDevice(ElectronicDevice device) {  
        totalPrice += device.getPrice();  
    }  
  
    // 获取总价格的方法  
    public double getTotalPrice() {  
        return totalPrice;  
    }  
}

6、实现打印信息行为的访问者

/**
 * 打印信息访问者类,实现了ProductVisitor接口
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2024/06/25
 */
class PrintInfoVisitor implements ProductVisitor {
    /**
     * 实现访问书籍的方法,打印书籍信息
     * @param book
     */
    @Override  
    public void visitBook(Book book) {  
        System.out.println("书籍信息: 标题=" + book.getTitle() + ", 作者=" + book.getAuthor() + ", 价格=" + book.getPrice());  
    }

    /**
     * 实现访问电子产品的方法,打印电子产品信息
     * @param device
     */
    @Override  
    public void visitElectronicDevice(ElectronicDevice device) {  
        System.out.println("电子产品信息: 型号=" + device.getModel() + ", 品牌=" + device.getBrand() + ", 价格=" + device.getPrice());  
    }  
}

7、编写测试类

8、测试结果

书籍信息: 标题=设计模式, 作者=第七人格, 价格=7.0

电子产品信息: 型号=HUAWEI Pura 70, 品牌=华为, 价格=6999.0

总价格: 7006.0

实现要点

  1. Visitor(访问者):接口或抽象类,定义了对每一个元素类(Element)的访问操作。

    ProductVisitor接口充当Visitor角色,它声明了访问不同产品类型的方法。

  2. ConcreteVisitor(具体访问者):实现了Visitor接口的类,它实现了对每个元素类的具体操作。

    PrintInfoVisitor和CalculatePriceVisitor类实现了这个接口,分别用于打印产品信息和计算产品价格。

  3. Element(元素):接口或抽象类,定义了一个接受访问者(Accept)的方法。

    对应代码示例中的Product接口。

  4. ConcreteElement(具体元素):实现了Element接口的类,它们通常包含一些状态信息,这些信息在访问时被传递给访问者。

    对应代码示例中的Book和ElectronicDevice类。

  5. ObjectStructure(对象结构):可以遍历元素集合,并负责提供访问者访问元素的方法。

    代码实例中没有这个对象结构,它持有产品的集合,并可以遍历这些产品,让访问者访问它们。我们可以提供这个方法给购物车。

总结

访问者模式允许我们在不改变数据结构的情况下增加新的操作。在我们的电子商务系统例子中,通过定义ProductVisitor接口和具体的访问者类,我们能够轻松地添加新的操作,如打印信息或计算价格,而无需修改现有的产品类。这提供了很大的灵活性,尤其是在需要频繁添加新功能或操作时。

转载自:https://juejin.cn/post/7383894687302303753
评论
请登录