访问者是一种行为设计模式,可让您将算法与它们操作的对象分开。
假设您有一个由各种几何形状组成的画布。您现在需要将画布导出为 XML 格式。您的计划是为每个几何形状类添加一个导出方法,然后遍历画布上的每个形状,执行导出方法。
在形状类中包含 XML 导出代码是否有意义?这些类主要负责在画布上显示坐标和使用坐标。
此外,很有可能有人会在该功能实施后要求能够以另一种格式导出。
访客设计模式
访问者模式建议您将新行为放入一个名为访问者的单独类中,而不是尝试将其集成到现有类中。现在,必须执行此行为的原始对象作为参数传递给访问者的方法,使该方法可以访问对象中包含的所有数据。
UML 类图
实施步骤
- 访问者接口应该用一组访问方法声明,程序中的每个具体元素类都有一个访问方法。
- 使用接受方法声明元素接口以接受访问者对象作为参数。
- 在所有具体元素类中实现接受方法。它必须简单地将调用重定向到与当前元素的类匹配的传入访问者对象上的访问方法。
- 访问者只能通过访问者界面与元素类进行交互。但是,访问者必须了解作为访问方法的参数类型引用的所有具体元素类。
- 每当无法在元素层次结构中实现行为时,创建一个新的具体访问者类并实现所有访问者方法。
- 客户端必须创建访问者对象并通过接受方法将它们传递给元素。
源代码实现
访问者接口定义了可以将对象结构的具体元素作为参数的访问方法。
package com.learncsdesign;
public interface Visitor {
public void visit(Dot dot);
public void visit(Rectangle rect);
public void visit(Circle circle);
}
具体访问者 XMLExportVisitor 实现了相同行为的多个版本,为不同的具体元素类量身定制。
package com.learncsdesign;
public class XMLExportVisitor implements Visitor {
@Override
public void visit(Dot dot) {
System.out.println(
"Exporting Dot ID and coordinates: ID: " + dot.getId() + ", x:" + dot.getX() + ", y:" + dot.getY());
}
@Override
public void visit(Rectangle rect) {
System.out.println("Exporting Dot ID and coordinates: ID: " + rect.getId() + ", x:" + rect.getX() + ", y:" + rect.getY());
}
@Override
public void visit(Circle circle) {
System.out.println("Exporting Dot ID and coordinates: ID: " + circle.getId() + ", x:" + circle.getX() + ", y:" + circle.getY());
}
}
Shape (Element) 接口声明了一个接受访问者的方法。 它应该有一个参数来声明访问者界面的类型。
package com.learncsdesign;
public interface Shape {
public void move(int x, int y);
public void draw();
public void accept(Visitor visitor);
}
Concrete Shapes Dot, Rectangle & Circle 必须各自实现验收方法。 此方法将调用重定向到与当前元素类对应的正确访问者方法。
package com.learncsdesign;
import java.util.Random;
public class Dot implements Shape {
private int id;
private int x;
private int y;
public Dot() {
this.id = new Random().nextInt(100000);
}
public int getId() {
return id;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
public void move(int x, int y) {
this.x += x;
this.y += y;
draw();
}
@Override
public void draw() {
System.out.println("Drawing Dot at (" + x + "," + y + ")");
}
@Override
public void accept(Visitor visitor) {
Visitor.visit(this);
}
}
package com.learncsdesign;
import java.util.Random;
public class Rectangle implements Shape {
private int id;
private int x;
private int y;
public Rectangle() {
this.id = new Random().nextInt(100000);
}
public int getId() {
return id;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
public void move(int x, int y) {
this.x += x;
this.y += y;
draw();
}
@Override
public void draw() {
System.out.println("Drawing Rectangle at (" + x + "," + y + ")");
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
package com.learncsdesign;
import java.util.Random;
public class Circle implements Shape {
private int id;
private int x;
private int y;
public Circle() {
this.id = new Random().nextInt(100000);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
public void move(int x, int y) {
this.x += x;
this.y += y;
draw();
}
@Override
public void draw() {
System.out.println("Drawing Circle at (" + x + "," + y + ")");
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
通常,客户端代表一个集合或一些其他复杂的对象。 在大多数情况下,客户端不知道所有具体的元素类,因为它们通过一些抽象接口处理来自该集合的对象。
package com.learncsdesign;
import java.util.LinkedList;
import java.util.List;
public class VisitorClient {
List<Shape> shapes;
public VisitorClient() {
shapes = new LinkedList<Shape>();
Dot dot = new Dot();
dot.move(10, 20);
shapes.add(dot);
Rectangle rect = new Rectangle();
rect.move(100, 0);
shapes.add(rect);
Circle circle = new Circle();
circle.move(234, 20);
shapes.add(circle);
}
public static void main(String[] args) {
VisitorClient client = new VisitorClient();
XMLExportVisitor exportVisitor = new XMLExportVisitor();
for (Shape shape : client.shapes) {
shape.accept(exportVisitor);
}
}
}
// Output
Drawing Dot at (10,20)
Drawing Rectangle at (100,0)
Drawing Circle at (234,20)
Exporting Dot ID and coordinates: ID: 63741, x:10, y:20
Exporting Dot ID and coordinates: ID: 29577, x:100, y:0
Exporting Dot ID and coordinates: ID: 2254, x:234, y:20
何时应用访客设计模式
- 当您需要对复杂对象结构的所有元素进行操作时,您应该使用访问者模式。
- 您可以使用访问者模式来清理辅助行为业务逻辑。 通过将所有其他行为提取到访问者类中,您可以使应用程序的主要类更加专注于它们的主要任务。
- 当行为仅在类层次结构的某些类中有意义而在其他类中不有意义时,该模式很有用。
访客设计模式的优点
- 通过引入一种新行为,您可以使用不同类的对象,而无需更改这些类。
- 同一行为的多个版本可以放在同一个类中。
- 当一个访问者对象与各种对象交互时,它可以积累一些有用的信息。 当您想要遍历一些复杂的对象结构(例如对象树)并将访问者应用于结构中的每个对象时,它会很方便。
更多APP/小程序/网站源码资源,请搜索"七爪网源码交易平台"!
如若转载,请注明出处:https://www.daxuejiayuan.com/38798.html