GoF 定义: Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure.
访问者模式讲的是表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
行为模式之一,目的是将行为 和对象 分开。
缺点:每增 加一种支持的 object,你就必须在 visitor 及其实现类中添加新的方法支持这个改动。
描述 被访问者就是上文中的 object,他持有数据,我们想把他和数据运算分离,保持其独立性
访问者代表着 operations,通过它可以实现数据运算
UML
实例 From DZone
抽象一个邮寄业务,计算购物车中所有的物件总的邮费。每样物件都有自己的属性,比如价格,重量之类的。我们将邮费计算的规则单独封装在 Visitor 中,在物件类中通过调用 accept 实现计算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 public interface Visitable { void accept (Visitor visitor) ; } public class Book implements Visitable { private double price = 8.0 ; private double weight = 3.2 ; @Override public void accept (Visitor visitor) { visitor.visit(this ); } public double getPrice () { return price; } public double getWeight () { return weight; } } public interface Visitor { void visit (Book book) ; void visit (Shoes shoes) ; } public class PostageVisitor implements Visitor { private double totalPostageForCart; @Override public void visit (Book book) { if (book.getPrice() < 10.0 ) { totalPostageForCart += book.getWeight() * 2 ; } } @Override public void visit (Shoes shoes) { public double getTotalPostageForCart () { return this .totalPostageForCart; } } public class Client { public static void main (String[] args) { Book book = new Book(); Shoes shoes = new Shoes(); PostageVisitor postageVisitor = new PostageVisitor(); book.accept(postageVisitor); shoes.accept(postageVisitor); System.out.println("Total cost: " + postageVisitor.getTotalPostageForCart()); } }
From Refactoring Guru
根据定义的图形打印信息到 XML 文件中,这个例子本质上和前一个没什么区别,但是他提供了组合类型的 object 支持,并且输出 xml, 还有 format 都让我眼前一亮。反正感觉很赞!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 public interface Shape { void move (int x, int y) ; void draw () ; String accept (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) { } @Override public void draw () { } public String accept (Visitor visitor) { return visitor.visitDot(this ); } } 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) { } @Override public void draw () { } public int getId () { return id; } @Override public String accept (Visitor visitor) { return visitor.visitCompoundGraphic(this ); } public void add (Shape shape) { children.add(shape); } } public interface Visitor { String visitDot (Dot dot) ; String visitCircle (Circle circle) ; String visitRectangle (Rectangle rectangle) ; String visitCompoundGraphic (CompoundShape cg) ; } 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 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 ); obj = " " + obj.replace("\n" , "\n " ) + "\n" ; sb.append(obj); } return sb.toString(); } } public class Client { 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)); } }