• 访问者模式:对象结构的元素处理


    欢迎来到设计模式系列的第十九篇文章,本篇将介绍访问者模式。访问者模式是一种行为型设计模式,它用于处理对象结构中不同类型的元素,而不需要修改这些元素的类。

    什么是访问者模式?

    访问者模式是一种将数据结构与数据操作分离的设计模式。在访问者模式中,我们定义了一个访问者(Visitor)类,该类包含一组访问方法,每个方法用于处理不同类型的元素。然后,我们可以为不同类型的元素定义一个元素类,并将这些元素传递给访问者进行处理。

    访问者模式的核心思想是在不修改元素类的情况下,通过访问者来实现对元素的操作。这种模式通常用于处理复杂对象结构,其中包含多种类型的元素,以及需要执行不同操作的需求。

    访问者模式的角色

    访问者模式涉及以下几个角色:

    1. 访问者(Visitor):访问者是一个接口或抽象类,它定义了一组访问方法,每个方法用于处理不同类型的元素。
    2. 具体访问者(Concrete Visitor):具体访问者是实现访问者接口的具体类,它实现了访问方法,用于对元素进行具体的处理。
    3. 元素(Element):元素是一个接口或抽象类,它定义了一个接受(Accept)方法,该方法接受一个访问者作为参数,以便访问者可以对该元素进行操作。
    4. 具体元素(Concrete Element):具体元素是实现元素接口的具体类,它实现了接受方法,并将自身作为参数传递给访问者。
    5. 对象结构(Object Structure):对象结构是一个包含多种类型元素的集合,它通常提供了一种方式来遍历这些元素,以便访问者可以对它们进行操作。

    为什么需要访问者模式?

    访问者模式的主要目的是将数据结构与数据操作分离,使得可以在不修改元素类的情况下,通过访问者来添加新的操作。这种模式适用于以下情况:

    1. 元素类的稳定性高:如果元素类的稳定性很高,很少需要修改,但需要添加新的操作,那么使用访问者模式可以避免修改元素类。
    2. 多种操作与元素的组合:如果存在多种不同类型的操作需要与多种不同类型的元素组合,访问者模式可以简化操作的管理。
    3. 封装性要求高:访问者模式可以将具体的操作封装在具体访问者中,使得元素类保持封装性,不暴露细节。

    访问者模式的实现

    让我们通过一个简单的示例来演示访问者模式的实现。考虑一个电商平台,有不同类型的商品,包括书籍、电子产品和食品。我们希望实现一个价格计算器,该计算器可以根据商品的类型和折扣策略计算最终价格。

    // 访问者接口
    interface Visitor {
        void visit(Book book);
        void visit(ElectronicProduct electronicProduct);
        void visit(Food food);
    }
    
    // 具体访问者
    class PriceCalculator implements Visitor {
        @Override
        public void visit(Book book) {
            double discount = book.getCategory().equals("Fiction") ? 0.2 : 0.1;
            double discountedPrice = book.getPrice() * (1 - discount);
            System.out.println("Price of " + book.getName() + ": $" + discountedPrice);
        }
    
        @Override
        public void visit(ElectronicProduct electronicProduct) {
            double discountedPrice = electronicProduct.getPrice() * 0.9;
            System.out.println("Price of " + electronicProduct.getName() + ": $" + discountedPrice);
        }
    
        @Override
        public void visit(Food food) {
            double discountedPrice = food.getPrice() * 0.95;
            System.out.println("Price of " + food.getName() + ": $" + discountedPrice);
        }
    }
    
    // 元素接口
    interface Element {
        void accept(Visitor visitor);
    }
    
    // 具体元素
    class Book implements Element {
        private String name;
        private String category;
        private double price;
    
        public Book(String name, String category, double price) {
            this.name = name;
            this.category = category;
            this.price = price;
        }
    
        public String getName() {
            return name;
        }
    
        public String getCategory() {
            return category;
        }
    
        public double getPrice() {
            return price;
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    }
    
    class ElectronicProduct implements Element {
        private String name;
        private double price;
    
        public ElectronicProduct(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        public String getName() {
            return name;
        }
    
        public double getPrice() {
            return price;
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    }
    
    class Food implements Element {
        private String name;
        private double price;
    
        public Food(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        public String getName() {
            return name;
        }
    
        public double getPrice() {
            return price;
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visit(this);
        }
    }
    
    // 对象结构
    class ShoppingCart {
        private List<Element> items = new ArrayList<>();
    
        public void addItem(Element item) {
            items.add(item);
        }
    
        public void accept(Visitor visitor) {
            for (Element item : items) {
                item.accept(visitor);
            }
        }
    }
    
    public class VisitorPatternExample {
        public static void main(String[] args) {
            ShoppingCart cart = new ShoppingCart();
            cart.addItem(new Book("The Great Gatsby", "Fiction", 15.99));
            cart.addItem(new ElectronicProduct("Smartphone", 499.99));
            cart.addItem(new Food("Chocolate", 4.99));
    
            Visitor priceCalculator = new PriceCalculator();
            cart.accept(priceCalculator);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137

    在这个示例中,我们定义了访问者接口 Visitor,并实现了具体访问者 PriceCalculator。元素接口 Element 定义了 accept 方法,用于接受访问者。每个具体元素类都实现了 accept 方法,并将自身传递给访问者。

    对象结构 ShoppingCart 包含了不同类型的商品元素,并提供了 accept 方法,用于遍历元素并调用访问者的方法。

    在示例的 main 方法中,我们创建了一个购物车 cart,并向其中添加了书籍、电子产品和食品。然后,我们创建了一个 PriceCalculator 访问者,并将购物车传递给它进行价格计算。

    访问者模式的优点

    访问者模式的优点包括:

    • 符合开闭原则:可以通过添加新的访问者来扩展操作,而无需修改元素类。
    • 将操作与元素分离:访问者模式可以将数据结构与数据操作分离,使元素类保持简洁,不包含操作的逻辑。
    • 支持多态行为:访问者模式利用多态性,使不同类型的元素可以有不同的操作,增加了灵活性。

    访问者模式的缺点

    访问者模式的缺点包括:

    • 增加了类的数量:引入访问者模式会增加访问者和元素类的数量,增加了代码的复杂性。
    • 不容易理解:访问者模式的结构相对复杂,可能不容易理解和维护。

    适用场景

    访问者模式适用于以下情况:

    • 当需要对复杂对象结构中的元素进行不同类型的操作,而且这些操作需要保持独立时。
    • 当元素类的稳定性高,不经常修改,但需要添加新的操作时。
    • 当希望在不修改元素类的情况下,增加新的操作或访问方式时。

    总结

    访问者模式是一种行为型设计模式,它将数据结构与数据操作分离,通过访问者来实现对元素的操作。这种模式在处理复杂对象结构和需要多种操作的情况下非常有用。虽然它增加了类的数量和代码的复杂性,但能够提供灵活性和可扩展性,符合开闭原则。在实际项目中,可以根据具体需求考虑是否使用访问者模式。

  • 相关阅读:
    【数字IC/FPGA】Verilog中的force和release
    2024年如何将小程序音频下载下来#下载高手
    跨境电商平台Etsy被封?那是因为你没做对这件事!
    【操作系统】Lesson1-什么是操作系统
    创建一个基本的win32窗口
    洛谷题解 | P1051 谁拿了最多奖学金
    在qml中的ShaderEffect在arm板的3568的系统上是用GPU渲染的吗
    【AI语音】九联UNT402A_通刷_纯净精简_免费线刷固件包
    Java设计模式(上)
    【css】H6_盒子模型
  • 原文地址:https://blog.csdn.net/weixin_45701550/article/details/133721741