软件设计模式系列之二十五——访问者模式

软件设计,模式,系列,之二,十五,访问者 · 浏览次数 : 9

小编点评

**访问者模式** **优缺点** **可扩展性** * 添加新的操作变得容易。 *无需修改已有的元素类。 **分离关注点** * 访问者对象负责定义要执行的操作。 * 遍历对象结构来执行这些操作。 **灵活性** * 可以定义多个不同的访问者,每个访问者执行不同的操作。 * 实现灵活的行为扩展。 **符合开闭原则** *可以在不修改已有代码的情况下添加新的访问者和操作。 **示例** ```java // 访问者模式 public class AccesserPattern { // 定义访问者对象 private Accesser accesser; // 定义操作 private Operation operation; // 构造访问者对象 public AccesserPattern(Accesser accesser, Operation operation) { this.accesser = accesser; this.operation = operation; } // 执行操作 public void executeOperation() { // 执行操作 operation.execute(); } } // 访问者对象 public class Accesser { // 访问对象 private Object object; // 构造访问器对象 public Accesser(Object object) { this.object = object; } // 获取对象 public Object getObject() { return object; } } // 操作接口 public interface Operation { void execute(); } // 操作类 public class Operation { // 执行操作 public void execute() { // 执行操作 } } ```

正文

访问者模式(Visitor Pattern)是一种强大的行为型设计模式,它允许你在不改变被访问对象的类的前提下,定义新的操作和行为。本文将详细介绍访问者模式,包括其定义、举例说明、结构、实现步骤、Java代码实现、典型应用场景、优缺点、类似模式以及最后的小结。

1 模式的定义

访问者模式允许你在不修改被访问对象的类的情况下,定义并封装一组新的操作。它通常用于处理对象结构中的元素,并能够在不改变这些元素的类的情况下,为这些元素添加新的操作。这种模式的关键思想是将操作与元素分离,使得增加新操作变得相对容易。

2 举例说明

访问者模式的思想在日常生活中有许多应用,以下是几个比较符合访问者模式且为大家所熟知的例子:

博物馆导览员:在博物馆中,导览员扮演着访问者的角色。博物馆中的艺术品、展品等可以被看作是元素,而导览员则是具体访问者。导览员可以根据参观者的需求,为他们提供不同的讲解、信息或故事,而不需要改变艺术品本身。

旅游团队:旅游团队的导游可以被看作是访问者,而游客可以被视为元素。导游可以根据游客的兴趣和需求,提供不同的旅游信息和体验,而不需要修改景点本身。

电子商务网站的购物车:在电子商务网站中,购物车可以被看作是对象结构,而购买的商品可以被视为元素。不同的访问者可以执行不同的操作,例如计算总价、生成订单等,而不需要修改商品类的代码。

这些例子都展示了访问者模式的核心思想:允许在不改变元素本身的情况下,为元素执行不同的操作。这种分离关注点的设计模式在实际生活中具有广泛的应用。

3 结构

访问者模式由以下主要组件组成:

访问者(Visitor):定义了要访问的对象的接口,包括访问不同类型对象的方法。

具体访问者(ConcreteVisitor):实现了访问者接口,定义了针对不同类型对象的具体操作。

元素(Element):定义了接受访问者访问的接口,通常包括一个 accept 方法,该方法接受访问者作为参数。

具体元素(ConcreteElement):实现了元素接口,它包含了 accept 方法的实现,该方法将自身传递给访问者以便进行操作。

对象结构(Object Structure):包含元素的集合,通常提供一个方法来遍历这些元素,访问者可以通过该方法访问元素。

4 实现步骤

实现访问者模式需要按照以下步骤进行:

定义元素接口(Element),其中包括一个接受访问者的方法(accept 方法)。

创建具体元素类(ConcreteElement),实现元素接口,并提供具体的操作。

定义访问者接口(Visitor),其中包括为每个具体元素类型定义的访问方法。

创建具体访问者类(ConcreteVisitor),实现访问者接口,并为每个具体元素类型提供具体的访问方法。

创建对象结构类(Object Structure),其中包含元素的集合,并提供一个方法用于访问元素。

在客户端代码中,创建具体元素的实例,将它们添加到对象结构中,并创建具体访问者的实例。

使用访问者对象来访问对象结构中的元素,从而执行具体的操作。

5 代码实现

以下是一个使用Java编写的访问者模式的示例代码:

// Step 1: 定义元素接口
interface Animal {
    void accept(Visitor visitor);
}

// Step 2: 创建具体元素类
class Dog implements Animal {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class Cat implements Animal {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// Step 3: 定义访问者接口
interface Visitor {
    void visit(Dog dog);
    void visit(Cat cat);
}

// Step 4: 创建具体访问者类
class HealthCheckupVisitor implements Visitor {
    @Override
    public void visit(Dog dog) {
        System.out.println("健康检查狗:" + dog.getClass().getSimpleName());
    }

    @Override
    public void visit(Cat cat) {
        System.out.println("健康检查猫:" + cat.getClass().getSimpleName());
    }
}

class InformationDisplayVisitor implements Visitor {
    @Override
    public void visit(Dog dog) {
        System.out.println("展示狗信息:" + dog.getClass().getSimpleName());
    }

    @Override
    public void visit(Cat cat) {
        System.out.println("展示猫信息:" + cat.getClass().getSimpleName());
    }
}

// Step 5: 创建对象结构类
class Zoo {
    private List<Animal> animals = new ArrayList<>();

    public void addAnimal(Animal animal) {
        animals.add(animal);
    }

    public void accept(Visitor visitor) {
        for (Animal animal : animals) {
            animal.accept(visitor);
        }
    }
}

// Step 6: 客户端代码
public class VisitorPatternExample {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        zoo.addAnimal(new Dog());
        zoo.addAnimal(new Cat());

        Visitor healthCheckupVisitor = new HealthCheckupVisitor();
        Visitor informationDisplayVisitor = new InformationDisplayVisitor();

        zoo.accept(healthCheckupVisitor);
        zoo.accept(informationDisplayVisitor);
    }
}

6 典型应用场景

访问者模式允许你在不修改现有对象结构的情况下,定义新操作并将其应用于这些对象。以下是一些典型的访问者模式应用场景:

  • 数据结构与操作分离。当你有一个复杂的数据结构,其中包含多种不同类型的对象,并且希望对这些对象执行各种操作,但不希望将操作的代码放在这些对象中时,访问者模式可以帮助你将操作与数据结构分离开来。

  • 数据结构稳定但操作频繁变化。如果数据结构相对稳定,但需要经常添加新的操作或修改现有操作,使用访问者模式可以轻松地添加新的访问者类而不必修改数据结构类。

  • 数据结构中对象类型多样化。当你的数据结构中包含多个不同的对象类型,且你需要对每种类型执行不同的操作时,访问者模式使得你可以轻松地扩展和管理这些操作。

  • 数据结构具有复杂的嵌套结构。如果你的数据结构是一个复杂的嵌套结构,其中对象可以包含子对象,访问者模式可以通过递归遍历整个结构,使得操作更容易实施。

  • 扩展性要求高。当你需要为系统提供高度可扩展性,以便能够随时添加新的操作和对象类型时,访问者模式是一个有用的选择,因为它使得添加新功能变得相对容易。

  • 数据结构和操作分布在不同的类库中。如果数据结构和操作分别位于不同的类库中,访问者模式可以帮助你通过定义新的访问者来扩展操作,而无需修改已有的类库。

访问者模式适用于需要对复杂对象结构进行多种不同操作的情况,同时又要保持数据结构的稳定性和可扩展性的需求。通过将操作封装在访问者对象中,它可以有效地解耦操作和数据结构,使得系统更加灵活和可维护。

7 优缺点

优点:

可扩展性。访问者模式使得添加新的操作变得容易,无需修改已有的元素类。
分离关注点。访问者模式将对象结构和操作分离,使得每个部分都可以独立变化,提高了代码的可维护性。
灵活性。可以定义多个不同的访问者,每个访问者执行不同的操作,从而实现灵活的行为扩展。
符合开闭原则。可以在不修改已有代码的情况下添加新的访问者和操作。

缺点:

增加复杂性。引入了访问者和元素之间的额外层次,可能会增加代码的复杂性。
不适用于小规模场景。在小规模场景下,使用访问者模式可能会显得繁琐和过于复杂。

8 类似模式

与访问者模式类似的模式包括以下几种:

  • 迭代器模式(Iterator Pattern):

迭代器模式和访问者模式都用于处理集合或对象结构中的元素。它们都允许你遍历集合中的元素,但它们的焦点不同。迭代器模式关注于提供一种访问元素的方法,而访问者模式关注于在元素上执行不同的操作。在迭代器模式中,通常有一个迭代器对象,它负责遍历集合并提供对元素的访问。而在访问者模式中,访问者对象负责定义要执行的操作,并遍历对象结构来执行这些操作。

  • 组合模式(Composite Pattern):

组合模式和访问者模式通常一起使用,以便在对象结构中执行操作。组合模式用于表示树形结构,而访问者模式用于在树形结构中执行操作。组合模式主要用于创建和管理树形结构,它使得可以像对待单个对象一样对待组合对象。访问者模式则用于在树形结构中执行不同的操作,将操作与对象分离。

  • 观察者模式(Observer Pattern):

观察者模式和访问者模式都属于行为型设计模式,它们都涉及多个对象之间的交互。观察者模式用于定义对象之间的一对多依赖关系,一个对象的状态变化会通知所有依赖它的对象。访问者模式用于在对象结构中执行不同的操作,与对象的状态变化无关。

这些模式之间的联系在于它们都处理对象之间的关系,但它们的焦点和用途不同。访问者模式主要用于在对象结构中执行不同的操作,而其他模式则更关注对象之间的交互、结构或组织。根据具体的问题和需求,你可以选择使用适合的模式来改善设计和实现。

9 小结

访问者模式是一种强大的设计模式,它可以使你轻松地添加新的操作,而不需要修改现有的元素类。通过将操作从元素类中分离出来,访问者模式提高了代码的可维护性和可扩展性。然而,它也可能会引入额外的复杂性,因此在小规模场景下使用时要谨慎。了解访问者模式的结构和实现步骤,以及它的优缺点和典型应用场景,将有助于你在适当的情况下使用这一模式来改善代码的设计和可维护性。

与软件设计模式系列之二十五——访问者模式相似的内容:

软件设计模式系列之二十五——访问者模式

访问者模式(Visitor Pattern)是一种强大的行为型设计模式,它允许你在不改变被访问对象的类的前提下,定义新的操作和行为。本文将详细介绍访问者模式,包括其定义、举例说明、结构、实现步骤、Java代码实现、典型应用场景、优缺点、类似模式以及最后的小结。

软件设计模式系列之二十四——模板方法模式

在软件设计领域,设计模式是一组被反复使用、多次实践验证的经典问题解决方案。其中,模板方法模式是一种行为型设计模式,用于定义一个算法的骨架,将算法中的某些步骤延迟到子类中实现,从而使子类可以重新定义算法的某些特定步骤,同时保持算法的整体结构不变。本文将深入探讨模板方法模式,包括其定义、举例、结构、实现...

软件设计模式系列之二十三——策略模式

策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时动态选择算法的行为。这意味着你可以定义一系列算法,将它们封装成独立的策略对象,然后根据需要在不修改客户端代码的情况下切换这些算法。策略模式有助于解决问题领域中不同行为的变化和扩展,同时保持代码的灵活性和可维护性。

软件设计模式系列之二十二——状态模式

状态模式是一种行为型设计模式,它允许对象在内部状态发生改变时改变其行为,使得对象的行为看起来像是改变了其类。状态模式将对象的状态抽象成一个独立的类,让对象在不同状态下具有不同的行为,而且可以在运行时切换状态。这种方式使得状态的管理更加清晰,避免了大量的条件判断语句,提高了代码的可维护性和可扩展性。

软件设计模式系列之二十一——观察者模式

观察者模式(Observer Pattern)是一种行为型设计模式,它允许对象之间建立一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。这个模式也被称为发布-订阅模式,因为它模拟了一个主题(发布者)与多个观察者(订阅者)之间的关系。观察者模式主要用于实现对象之间...

软件设计模式系列之二十——备忘录模式

备忘录模式是一种行为型设计模式,它允许我们在不暴露对象内部细节的情况下捕获和恢复对象的内部状态。这个模式非常有用,因为它可以帮助我们实现撤销、恢复和历史记录等功能。在本文中,我们将深入探讨备忘录模式的各个方面,包括定义、示例、结构、实现步骤、代码实现、典型应用场景、优缺点、类似模式以及小结。

软件设计模式系列之十五——职责链模式

职责链模式(Chain of Responsibility Pattern)也称为责任链模式,是一种结构型设计模式,用于构建一条对象处理请求的责任链。在这个模式中,多个对象依次处理请求,直到其中一个对象能够处理该请求为止。职责链模式将请求的发送者和接收者解耦,允许多个对象都有机会处理请求,同时可以动...

软件设计模式系列之十一——装饰模式

装饰模式属于结构型设计模式,它通过将对象包装在装饰器类中来动态地添加额外的行为,而不需要修改原始对象的代码。这个模式以透明的方式向对象添加功能,从而使您可以根据需要组合各种功能。

软件设计模式系列之十二——外观模式

外观模式是一种结构型设计模式,它提供了一个简化的接口,用于访问系统中的一组相关接口,以隐藏系统的复杂性。外观模式的主要目标是简化客户端与子系统之间的交互,同时降低了系统的耦合度。它允许客户端通过一个统一的入口点来与系统进行通信,而不需要了解系统内部的具体细节和复杂性

软件设计模式系列之十三——享元模式

享元模式(Flyweight Pattern)是一种结构型设计模式,它旨在减少内存占用或计算开销,通过共享大量细粒度对象来提高系统的性能。这种模式适用于存在大量相似对象实例,但它们的状态可以外部化(extrinsic),并且可以在多个对象之间共享的情况。