设计模式-访问者模式
设计模式专栏

    • 模式介绍
    • 模式特点
    • 应用场景
    • 访问者模式和单例模式的区别
    • 代码示例
      • Java实现访问者模式
      • python实现访问者模式
    • 单例模式在spring中的应用


模式介绍

访问者模式是一种行为型设计模式,它提供了一种方式,可以在不改变各元素类的前提下定义作用于这些元素的新操作。这种模式适用于数据结构相对稳定,而操作易于变化的情况。

访问者模式的主要组成部分包括访问者和被访问元素。被访问元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。例如,处方单中的各种药品信息就是被访问的元素,而划价人员和药房工作人员就是访问者。

在使用访问者模式时,被访问元素通常不是单独存在的,它们存储在一个集合中,这个集合被称为“对象结构”,访问者通过遍历对象结构实现对其中存储的元素的逐个操作。

访问者模式的好处在于,它使得用户可以在不修改现有系统的情况下扩展系统的功能,为这些不同类型的元素增加新的操作。同时,它也提高了系统的可维护性和可扩展性。

在这里插入图片描述

模式特点

访问者模式的主要特点包括:

  1. 扩展性好 :能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  2. 复用性好 :可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
  3. 灵活性好 :访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
  4. 符合单一职责原则 :把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。

在这里插入图片描述

应用场景

访问者模式的应用场景主要包括:

  1. 对象结构中包含很多不同类型的对象,希望对这些对象实施一些依赖于其具体类的操作。
  2. 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类。

在这些场景中,访问者模式提供了一种解决方案,它允许你在不改变元素类的前提下定义作用于这些元素的新操作。访问者模式将相关的行为封装到一个访问者对象中,让你能够在不修改对象结构的情况下添加新的操作。

需要注意的是,访问者模式并不适用于所有情况。例如,当系统需要频繁地增加新的数据结构或者元素的变更较为困难时,访问者模式可能不是最佳选择。因为在这种情况下,每增加一个新的数据结构都需要修改访问者接口和所有访问者类,这会导致系统变得非常复杂和难以维护。

在这里插入图片描述

访问者模式和单例模式的区别

访问者模式和单例模式是两种不同的设计模式,它们在实现方式、应用场景和目的上存在明显的区别。

  1. 实现方式:

    • 访问者模式:通过定义一个访问者接口,让具体元素类实现该接口,并允许访问者对象访问具体元素类的对象。
    • 单例模式:通过定义一个单例类,该类提供一个全局访问点来获取该类的唯一实例。
  2. 应用场景:

    • 访问者模式:适用于一个对象结构中包含多种类型的元素,需要定义多个操作来作用于这些元素,且不希望修改元素类的场景。
    • 单例模式:适用于需要保证一个类仅有一个实例,并提供一个访问它的全局访问点的场景。
  3. 目的:

    • 访问者模式:通过将操作与对象结构分离,使得添加新的操作不需要修改对象结构,提高系统的灵活性和可扩展性。
    • 单例模式:通过确保一个类仅有一个实例,避免重复创建和销毁对象,节省内存资源,保证数据内容的一致性。

总的来说,访问者模式和单例模式都是常见的设计模式,它们在解决问题时各有侧重。访问者模式注重对元素对象的操作进行解耦,而单例模式则关注如何确保一个类只有一个实例。

在这里插入图片描述

代码示例

Java实现访问者模式

以下是一个使用Java实现访问者模式的示例:

首先,我们定义元素接口Element和具体元素类ConcreteElement

public interface Element {void accept(Visitor visitor);
}public class ConcreteElement implements Element {private String name;public ConcreteElement(String name) {this.name = name;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public String getName() {return name;}
}

然后,我们定义访问者接口Visitor和具体访问者类ConcreteVisitor

public interface Visitor {void visit(ConcreteElement element);
}public class ConcreteVisitor implements Visitor {@Overridepublic void visit(ConcreteElement element) {System.out.println("Visiting element: " + element.getName());}
}

最后,我们定义对象结构类ObjectStructure,它包含了一个元素集合,并提供了一个接受访问者的方法:

import java.util.ArrayList;
import java.util.List;public class ObjectStructure {private List<Element> elements = new ArrayList<>();public void attach(Element element) {elements.add(element);}public void detach(Element element) {elements.remove(element);}public void accept(Visitor visitor) {for (Element element : elements) {element.accept(visitor);}}
}

现在我们可以使用这些类来实现访问者模式了。下面是一个简单的示例:

public class Client {public static void main(String[] args) {ObjectStructure objectStructure = new ObjectStructure();objectStructure.attach(new ConcreteElement("Element 1"));objectStructure.attach(new ConcreteElement("Element 2"));objectStructure.attach(new ConcreteElement("Element 3"));Visitor visitor = new ConcreteVisitor();objectStructure.accept(visitor); // 输出:Visiting element: Element 1, Visiting element: Element 2, Visiting element: Element 3}
}

在这个示例中,我们首先创建了一个ObjectStructure对象,并向其中添加了三个ConcreteElement对象。然后,我们创建了一个ConcreteVisitor对象,并将其传递给ObjectStructureaccept()方法。这个方法会遍历对象结构中的所有元素,并对每个元素调用其accept()方法,传递访问者对象。最终,每个元素都会调用访问者的visit()方法,实现对元素的访问操作。

python实现访问者模式

以下是一个使用Python实现访问者模式的示例:

首先,我们定义元素接口Element和具体元素类ConcreteElement

from abc import ABC, abstractmethodclass Element(ABC):@abstractmethoddef accept(self, visitor):pass
class ConcreteElement(Element):def __init__(self, name):self.name = namedef accept(self, visitor):visitor.visit(self)

然后,我们定义访问者接口Visitor和具体访问者类ConcreteVisitor

from abc import ABC, abstractmethodclass Visitor(ABC):@abstractmethoddef visit(self, element):pass
class ConcreteVisitor(Visitor):def visit(self, element):print(f"Visiting element: {element.name}")

最后,我们定义对象结构类ObjectStructure,它包含了一个元素集合,并提供了一个接受访问者的方法:

class ObjectStructure:def __init__(self):self.elements = []def attach(self, element):self.elements.append(element)def detach(self, element):self.elements.remove(element)def accept(self, visitor):for element in self.elements:element.accept(visitor)

现在我们可以使用这些类来实现访问者模式了。下面是一个简单的示例:

if __name__ == "__main__":object_structure = ObjectStructure()object_structure.attach(ConcreteElement("Element 1"))object_structure.attach(ConcreteElement("Element 2"))object_structure.attach(ConcreteElement("Element 3"))visitor = ConcreteVisitor()object_structure.accept(visitor) # 输出:Visiting element: Element 1, Visiting element: Element 2, Visiting element: Element 3

在这里插入图片描述

单例模式在spring中的应用

访问者模式在Spring框架中的应用主要体现在数据访问层(DAO层)和业务逻辑层(Service层)之间的交互。

在Spring框架中,DAO层通常负责与数据库进行交互,而Service层则负责处理业务逻辑。当Service层需要访问数据库时,它可以通过访问DAO层来获取数据。

访问者模式在这个过程中扮演了重要的角色。在访问者模式中,一个对象结构可以接受多个访问者,每个访问者可以访问结构中的元素并执行相应的操作。在Spring框架中,Service层可以作为访问者,DAO层可以作为对象结构。

当Service层需要访问数据库时,它可以通过调用DAO层的方法来获取数据。DAO层中的方法通常返回一个集合(如List、Set等),这些集合中的元素可以是各种数据类型(如User、Order等)。Service层可以通过遍历这些集合并对每个元素执行相应的操作来处理数据。

在Spring框架中,访问者模式的应用还体现在事务管理上。Spring框架提供了声明式事务管理功能,允许开发者在代码中无需显式编写事务管理代码。当Service层需要执行事务操作时,它可以通过调用DAO层的方法来执行数据库操作。在事务管理过程中,Spring框架会自动对事务进行回滚、提交等操作,以确保数据的完整性和一致性。

访问者模式在Spring框架中的应用主要体现在数据访问层和业务逻辑层之间的交互以及事务管理上。通过使用访问者模式,Spring框架能够提供更加灵活和可扩展的数据访问和业务逻辑处理方式。

在这里插入图片描述