访问者模式(visitor pattern):当你想要为一个对象的组合增加新的能力,且封装并不重要时,就使用访问者模式。把”作用于对象结构上的操作”封装成访问者,新增操作时只需新增一个访问者实现,无需改动元素类。
意图
为一个对象结构(比如组合结构)增加新能力。
类图
- Visitor:访问者,为每一个 ConcreteElement 声明一个 visit 操作
- ConcreteVisitor:具体访问者,存储遍历过程中的累计结果
- ObjectStructure:对象结构,可以是组合结构,或者是一个集合
原文图片丢失,据文字重绘。
classDiagram
class Element {
<<interface>>
+accept(Visitor)
}
class Customer {
-String name
-List~Order~ orders
+accept(Visitor)
}
class Order {
-String name
-List~Item~ items
+accept(Visitor)
}
class Item {
-String name
+accept(Visitor)
}
class CustomerGroup {
-List~Customer~ customers
+accept(Visitor)
+addCustomer(Customer)
}
class Visitor {
<<interface>>
+visit(Customer)
+visit(Order)
+visit(Item)
}
class GeneralReport {
-int customersNo
-int ordersNo
-int itemsNo
+visit(Customer)
+visit(Order)
+visit(Item)
+displayResults()
}
Element <|.. Customer
Element <|.. Order
Element <|.. Item
Visitor <|.. GeneralReport
CustomerGroup o-- Customer
Customer o-- Order
Order o-- Item
CustomerGroup ..> Visitor
Element ..> Visitor : accept
实现
元素接口和一组组成对象结构的元素:Customer(客户)、Order(订单)、Item(条目),每个元素的 accept() 把自己交给访问者,并让访问者继续访问子元素:
public interface Element {
void accept(Visitor visitor);
}
public class Customer implements Element {
private String name;
private List<Order> orders = new ArrayList<>();
Customer(String name) {
this.name = name;
}
String getName() {
return name;
}
void addOrder(Order order) {
orders.add(order);
}
public void accept(Visitor visitor) {
visitor.visit(this);
for (Order order : orders) {
order.accept(visitor);
}
}
}
public class Order implements Element {
private String name;
private List<Item> items = new ArrayList();
Order(String name) {
this.name = name;
}
Order(String name, String itemName) {
this.name = name;
this.addItem(new Item(itemName));
}
String getName() {
return name;
}
void addItem(Item item) {
items.add(item);
}
public void accept(Visitor visitor) {
visitor.visit(this);
for (Item item : items) {
item.accept(visitor);
}
}
}
public class Item implements Element {
private String name;
Item(String name) {
this.name = name;
}
String getName() {
return name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
对象结构 CustomerGroup,遍历所有元素并让它们接受访问:
class CustomerGroup {
private List<Customer> customers = new ArrayList<>();
void accept(Visitor visitor) {
for (Customer customer : customers) {
customer.accept(visitor);
}
}
void addCustomer(Customer customer) {
customers.add(customer);
}
}
访问者接口和具体访问者 GeneralReport,在遍历过程中累计统计结果:
public interface Visitor {
void visit(Customer customer);
void visit(Order order);
void visit(Item item);
}
public class GeneralReport implements Visitor {
private int customersNo;
private int ordersNo;
private int itemsNo;
public void visit(Customer customer) {
System.out.println(customer.getName());
customersNo++;
}
public void visit(Order order) {
System.out.println(order.getName());
ordersNo++;
}
public void visit(Item item) {
System.out.println(item.getName());
itemsNo++;
}
public void displayResults() {
System.out.println("Number of customers: " + customersNo);
System.out.println("Number of orders: " + ordersNo);
System.out.println("Number of items: " + itemsNo);
}
}
public class Client {
public static void main(String[] args) {
Customer customer1 = new Customer("customer1");
customer1.addOrder(new Order("order1", "item1"));
customer1.addOrder(new Order("order2", "item1"));
customer1.addOrder(new Order("order3", "item1"));
Order order = new Order("order_a");
order.addItem(new Item("item_a1"));
order.addItem(new Item("item_a2"));
order.addItem(new Item("item_a3"));
Customer customer2 = new Customer("customer2");
customer2.addOrder(order);
CustomerGroup customers = new CustomerGroup();
customers.addCustomer(customer1);
customers.addCustomer(customer2);
GeneralReport visitor = new GeneralReport();
customers.accept(visitor);
visitor.displayResults();
}
}
输出:
customer1
order1
item1
order2
item1
order3
item1
customer2
order_a
item_a1
item_a2
item_a3
Number of customers: 2
Number of orders: 4
Number of items: 6
想增加另一种报表,只需要再实现一个 Visitor,元素类和对象结构都不用改动——这就是访问者模式为对象结构增加新能力的方式。
JDK 中的应用
- javax.lang.model.element.Element 与 javax.lang.model.element.ElementVisitor
- javax.lang.model.type.TypeMirror 与 javax.lang.model.type.TypeVisitor
系列导航
- 上一篇:模板方法(Template Method)
- 回到开篇:设计模式知识体系详解(行为型 11 篇到此完成,本系列完结)