Patrón Visitante

En el patrón visitante (Visitor Pattern), usamos una clase visitante que cambia el algoritmo de ejecución de las clases de elementos. De esta manera, el algoritmo de ejecución de un elemento puede cambiar según el visitante. Este tipo de patrón de diseño pertenece a los patrones de comportamiento. Según el patrón, el objeto elemento acepta al objeto visitante, de modo que el objeto visitante puede manejar las operaciones sobre el objeto elemento.

Introducción

Intención

Pretende separar la estructura de datos de las operaciones realizadas sobre ella, lo que facilita añadir nuevas operaciones sin modificar la estructura de datos en sí.

Problema principal que resuelve

  • Resuelve el problema de acoplamiento entre una estructura de datos estable y operaciones volátiles, permitiendo que las operaciones cambien independientemente de la estructura de datos.

Escenarios de uso

  • Cuando es necesario realizar múltiples operaciones diferentes y no relacionadas sobre los objetos de una estructura de objetos, especialmente cuando estas operaciones deben evitar "contaminar" la clase del objeto en sí.

Método de implementación

  • Definir la interfaz del visitante: declarar una serie de métodos de acceso, cada método de acceso corresponde a una clase de elemento en la estructura de datos.
  • Crear visitante concreto: implementar la interfaz del visitante, proporcionando una implementación concreta para cada método de acceso.
  • Definir la interfaz del elemento: declarar un método que acepte un visitante.
  • Crear elemento concreto: implementar la interfaz del elemento, cada clase de elemento concreto corresponde a un objeto concreto en la estructura de datos.

Código clave

  • Interfaz del visitante: contiene métodos para visitar diferentes elementos.
  • Visitante concreto: implementa la interfaz del visitante, incluye la lógica de acceso para cada clase de elemento.
  • Interfaz del elemento: contiene un método que acepta un visitante.
  • Elemento concreto: implementa la interfaz del elemento, proporciona la entrada para que el visitante acceda.

Ejemplo de aplicación

  • Escenario de visita: el visitante (como usted) visita la casa de un amigo; el amigo, como elemento, proporciona información, y el visitante toma decisiones según la información.

Ventajas

  • Principio de responsabilidad única: el patrón visitante cumple con el principio de responsabilidad única; cada clase es responsable de una sola tarea.
  • Extensibilidad: es fácil añadir nuevas operaciones a la estructura de datos.
  • Flexibilidad: el visitante puede cambiar independientemente de la estructura de datos.

Desventajas

  • Viola el principio de Demeter: los elementos necesitan exponer su información interna al visitante.
  • Las clases de elementos son difíciles de cambiar: las clases de elementos deben mantener compatibilidad con el visitante.
  • Dependencia de clases concretas: el patrón visitante depende de clases concretas en lugar de interfaces, lo que viola el principio de inversión de dependencias.

Recomendaciones de uso

  • Cuando la estructura de objetos es estable, pero se necesitan definir múltiples operaciones nuevas sobre ella, considere usar el patrón visitante.
  • Cuando sea necesario evitar que las operaciones "contaminen" las clases de objetos, use el patrón visitante para encapsular las operaciones.

Precauciones

  • El patrón visitante puede usarse para funcionalidades unificadas, como generación de informes, visualización de interfaces de usuario, interceptores y filtros, etc.

Principales roles involucrados

  • Visitante (Visitor):

    • Define la interfaz para visitar elementos.
  • Visitante concreto (Concrete Visitor):

    • Implementa la interfaz del visitante, proporcionando acceso y operaciones correspondientes para cada clase de elemento concreto.
  • Elemento (Element):

    • Define un método que acepta un visitante.
  • Elemento concreto (Concrete Element):

    • Implementa la interfaz del elemento y proporciona unacceptmétodo que permite al visitante acceder y operar.
  • Estructura de objetos (Object Structure) (opcional):

    • Define cómo ensamblar los elementos concretos, como una clase compuesta.
  • Cliente (Client) (opcional):

    • Usa el patrón visitante para operar sobre la estructura de objetos.

Implementación

Crearemos unaComputerPartinterfaz que define la operación de aceptación.Keyboard、Mouse、MonitoryComputerimplementaComputerPartla interfaz de la clase de entidad.ComputerPartVisitorDefiniremos otra interfazComputer, que define las operaciones de la clase visitante.

VisitorPatternDemoUsamos un visitante concreto para ejecutar las acciones correspondientes.Computer、ComputerPartVisitor, nuestra clase de demostración usa

访问者模式的 UML 图

Paso 1

Paso 1

ComputerPart.java

public interface ComputerPart { public void accept(ComputerPartVisitor computerPartVisitor); }

Paso 2

Paso 2

Keyboard.java

public class Keyboard implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } }

Monitor.java

public class Monitor implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } }

Mouse.java

public class Mouse implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } }

Computer.java

public class Computer implements ComputerPart { ComputerPart[] parts; public Computer(){ parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()}; } @Override public void accept(ComputerPartVisitor computerPartVisitor) { for (int i = 0; i < parts.length; i++) { parts[i].accept(computerPartVisitor); } computerPartVisitor.visit(this); } }

Paso 3

Paso 3

ComputerPartVisitor.java

public interface ComputerPartVisitor { public void visit(Computer computer); public void visit(Mouse mouse); public void visit(Keyboard keyboard); public void visit(Monitor monitor); }

Paso 4

Paso 4

ComputerPartDisplayVisitor.java

public class ComputerPartDisplayVisitor implements ComputerPartVisitor { @Override public void visit(Computer computer) { System.out.println("Displaying Computer."); } @Override public void visit(Mouse mouse) { System.out.println("Displaying Mouse."); } @Override public void visit(Keyboard keyboard) { System.out.println("Displaying Keyboard."); } @Override public void visit(Monitor monitor) { System.out.println("Displaying Monitor."); } }

Paso 5

Paso 5ComputerPartDisplayVisitorUsarComputerpara mostrar

VisitorPatternDemo.java

public class VisitorPatternDemo { public static void main(String[] args) { ComputerPart computer = new Computer(); computer.accept(new ComputerPartDisplayVisitor()); } }

Paso 6

Ejecutar el programa y mostrar el resultado:

Displaying Mouse.
Displaying Keyboard.
Displaying Monitor.
Displaying Computer.
Otras extensiones