Java設計模式(二十三):訪問者設計模式
阿新 • • 發佈:2019-01-11
1. 應用場景
對於系統中的某些物件,它們儲存在同一個集合中,且具有不同的型別,而且對於該集合中的物件,可以接受一類稱為訪問者的物件來訪問,而且不同的訪問者其訪問方式有所不同,訪問者模式為解決這類問題而誕生。
在實際使用時,對同一集合物件的操作並不是唯一的,對相同的元素物件可能存在多種不同的操作方式。而且這些操作方式並不穩定,可能還需要增加新的操作,以滿足新的業務需求。此時,訪問者模式就是一個值得考慮的解決方案。
訪問者模式的目的是封裝一些施加於某種資料結構元素之上的操作,一旦這些操作需要修改的話,接受這個操作的資料結構可以保持不變。為不同型別的元素提供多種訪問操作方式,且可以在不修改原有系統的情況下增加新的操作方式,這就是訪問者模式的模式動機。
2.概念
表示一個作用於某物件結構中的各元素的操作,它使我們可以在不改變各元素的類的前提下定義作用於這些元素的新操作。訪問者模式是一種物件行為型模式。
3. Class Diagram
- Visitor:訪問者,為每一個 ConcreteElement 宣告一個 visit 操作
- ConcreteVisitor:具體訪問者,儲存遍歷過程中的累計結果
- ObjectStructure:物件結構,可以是組合結構,或者是一個集合。
4. Implementation
public interface Element {
void accept (Visitor visitor);
}
public class Item {
private String name;
public Item(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class Order implements Element {
private String name;
private List<Item> items = new ArrayList();
public Order(String name) {
this.name = name;
}
public Order(String name, String itemName) {
this.name = name;
this.addItem(new Item(itemName));
}
public String getName() {
return name;
}
public void addItem(Item item) {
items.add(item);
}
public void accept(Visitor visitor) {
visitor.visit(this);
for (Item item : items) {
item.accept(visitor);
}
}
}
public class Customer implements Element{
private String name;
private List<Order> orders = new ArrayList<>();
public Customer(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void addOrder(Order order) {
orders.add(order);
}
public void accept(Visitor visitor) {
visitor.visit(this);
for (Order order : orders) {
order.accept(visitor);
}
}
}
public class CustomerGroup implements Element{
private List<Customer> customers = new ArrayList<>();
public void accept(Visitor visitor) {
for (Customer customer : customers) {
customer.accept(visitor);
}
}
public void addCustomer(Customer customer) {
customers.add(customer);
}
}
public interface Visitor {
public void visit(Customer customer);
public void visit(Order order);
public 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
5. 優點和缺點
5.1 優點
- 允許你對組合結構加入新的操作,而無需改變結構本身。
- 想要加入新的操作,想到容易
- 訪問者所進行的操作,其程式碼是集中在一起的。
5.2 用途和缺點
- 當採用訪問者模式的時候,就會打破組合類的封裝
- 因為遊走的功能牽連其中,所以對組合結構的改變就更加困難
6. JDK
- javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
- javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor