Visitor es un patrón de diseño de comportamiento que permite añadir nuevos comportamientos a una jerarquía de clases existente sin alterar el código.
Lee por qué el patrón Visitor no puede simplemente sustituirse por la sobrecarga de métodos, en nuestro artículo Visitor y envío doble .
Complejidad:
Popularidad:
Ejemplos de uso: El patrón Visitor no es muy habitual debido a su complejidad y limitada aplicabilidad.
Here are some examples of pattern in core Java libraries:Aquí tienes algunos ejemplos del patrón en las principales bibliotecas Java:
Exportar formas a XML
En este ejemplo, queremos exportar un grupo de formas geométricas a XML. La idea es que no queremos cambiar directamente el código de las formas o, al menos, debemos intentar mantener los cambios al mínimo.
Al fin y al cabo, el patrón Visitor establece una infraestructura que nos permite añadir cualquier comportamiento a la jerarquía de formas sin cambiar el código existente de esas clases.
shapes shapes/Shape.java: Interfaz común de las formas
package refactoring_guru.visitor.example.shapes;
import refactoring_guru.visitor.example.visitor.Visitor;
public interface Shape {
void move(int x, int y);
void draw();
String accept(Visitor visitor);
}
shapes/Dot.java: Un punto
package refactoring_guru.visitor.example.shapes;
import refactoring_guru.visitor.example.visitor.Visitor;
public class Dot implements Shape {
private int id;
private int x;
private int y;
public Dot() {
}
public Dot(int id, int x, int y) {
this.id = id;
this.x = x;
this.y = y;
}
@Override
public void move(int x, int y) {
// move shape
}
@Override
public void draw() {
// draw shape
}
@Override
public String accept(Visitor visitor) {
return visitor.visitDot(this);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getId() {
return id;
}
}
shapes/Circle.java: Un círculo
package refactoring_guru.visitor.example.shapes;
import refactoring_guru.visitor.example.visitor.Visitor;
public class Circle extends Dot {
private int radius;
public Circle(int id, int x, int y, int radius) {
super(id, x, y);
this.radius = radius;
}
@Override
public String accept(Visitor visitor) {
return visitor.visitCircle(this);
}
public int getRadius() {
return radius;
}
}
shapes/Rectangle.java: Un rectángulo
package refactoring_guru.visitor.example.shapes;
import refactoring_guru.visitor.example.visitor.Visitor;
public class Rectangle implements Shape {
private int id;
private int x;
private int y;
private int width;
private int height;
public Rectangle(int id, int x, int y, int width, int height) {
this.id = id;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public String accept(Visitor visitor) {
return visitor.visitRectangle(this);
}
@Override
public void move(int x, int y) {
// move shape
}
@Override
public void draw() {
// draw shape
}
public int getId() {
return id;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
shapes/CompoundShape.java: Una forma compuesta
package refactoring_guru.visitor.example.shapes;
import refactoring_guru.visitor.example.visitor.Visitor;
import java.util.ArrayList;
import java.util.List;
public class CompoundShape implements Shape {
public int id;
public List<Shape> children = new ArrayList<>();
public CompoundShape(int id) {
this.id = id;
}
@Override
public void move(int x, int y) {
// move shape
}
@Override
public void draw() {
// draw shape
}
public int getId() {
return id;
}
@Override
public String accept(Visitor visitor) {
return visitor.visitCompoundGraphic(this);
}
public void add(Shape shape) {
children.add(shape);
}
}
visitor visitor/Visitor.java: Interfaz visitante común
package refactoring_guru.visitor.example.visitor;
import refactoring_guru.visitor.example.shapes.Circle;
import refactoring_guru.visitor.example.shapes.CompoundShape;
import refactoring_guru.visitor.example.shapes.Dot;
import refactoring_guru.visitor.example.shapes.Rectangle;
public interface Visitor {
String visitDot(Dot dot);
String visitCircle(Circle circle);
String visitRectangle(Rectangle rectangle);
String visitCompoundGraphic(CompoundShape cg);
}
visitor/XMLExportVisitor.java: Visitante concreto, exporta todas las formas a XML
package refactoring_guru.visitor.example.visitor;
import refactoring_guru.visitor.example.shapes.*;
public class XMLExportVisitor implements Visitor {
public String export(Shape... args) {
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "\n");
for (Shape shape : args) {
sb.append(shape.accept(this)).append("\n");
}
return sb.toString();
}
public String visitDot(Dot d) {
return "<dot>" + "\n" +
" <id>" + d.getId() + "</id>" + "\n" +
" <x>" + d.getX() + "</x>" + "\n" +
" <y>" + d.getY() + "</y>" + "\n" +
"</dot>";
}
public String visitCircle(Circle c) {
return "<circle>" + "\n" +
" <id>" + c.getId() + "</id>" + "\n" +
" <x>" + c.getX() + "</x>" + "\n" +
" <y>" + c.getY() + "</y>" + "\n" +
" <radius>" + c.getRadius() + "</radius>" + "\n" +
"</circle>";
}
public String visitRectangle(Rectangle r) {
return "<rectangle>" + "\n" +
" <id>" + r.getId() + "</id>" + "\n" +
" <x>" + r.getX() + "</x>" + "\n" +
" <y>" + r.getY() + "</y>" + "\n" +
" <width>" + r.getWidth() + "</width>" + "\n" +
" <height>" + r.getHeight() + "</height>" + "\n" +
"</rectangle>";
}
public String visitCompoundGraphic(CompoundShape cg) {
return "<compound_graphic>" + "\n" +
" <id>" + cg.getId() + "</id>" + "\n" +
_visitCompoundGraphic(cg) +
"</compound_graphic>";
}
private String _visitCompoundGraphic(CompoundShape cg) {
StringBuilder sb = new StringBuilder();
for (Shape shape : cg.children) {
String obj = shape.accept(this);
// Proper indentation for sub-objects.
obj = " " + obj.replace("\n", "\n ") + "\n";
sb.append(obj);
}
return sb.toString();
}
}
Demo.java: Código cliente
package refactoring_guru.visitor.example;
import refactoring_guru.visitor.example.shapes.*;
import refactoring_guru.visitor.example.visitor.XMLExportVisitor;
public class Demo {
public static void main(String[] args) {
Dot dot = new Dot(1, 10, 55);
Circle circle = new Circle(2, 23, 15, 10);
Rectangle rectangle = new Rectangle(3, 10, 17, 20, 30);
CompoundShape compoundShape = new CompoundShape(4);
compoundShape.add(dot);
compoundShape.add(circle);
compoundShape.add(rectangle);
CompoundShape c = new CompoundShape(5);
c.add(dot);
compoundShape.add(c);
export(circle, compoundShape);
}
private static void export(Shape... shapes) {
XMLExportVisitor exportVisitor = new XMLExportVisitor();
System.out.println(exportVisitor.export(shapes));
}
}
OutputDemo.txt: Resultado de la ejecución
<?xml version="1.0" encoding="utf-8"?>
<circle>
<id>2</id>
<x>23</x>
<y>15</y>
<radius>10</radius>
</circle>
<?xml version="1.0" encoding="utf-8"?>
<compound_graphic>
<id>4</id>
<dot>
<id>1</id>
<x>10</x>
<y>55</y>
</dot>
<circle>
<id>2</id>
<x>23</x>
<y>15</y>
<radius>10</radius>
</circle>
<rectangle>
<id>3</id>
<x>10</x>
<y>17</y>
<width>20</width>
<height>30</height>
</rectangle>
<compound_graphic>
<id>5</id>
<dot>
<id>1</id>
<x>10</x>
<y>55</y>
</dot>
</compound_graphic>
</compound_graphic>