訪問者模式:表示一個做用於某對象結構中的各元素的操做。它使你能夠在不改變各元素類的前提下定義做用於這些元素的新操做。java
訪問者涉及到的角色:數據結構
1.Visitor 抽象訪問者角色,爲該對象結構中具體元素角色聲明一個訪問操做接口。該操做接口的名字和參數標識了發送訪問請求給具體訪問者的具體元素角色,這樣訪問者就能夠經過該元素角色的特定接口直接訪問它。ide
2.ConcreteVisitor.具體訪問者角色,實現Visitor聲明的接口。測試
3.Element 定義一個接受訪問操做(accept()),它以一個訪問者(Visitor)做爲參數。this
4.ConcreteElement 具體元素,實現了抽象元素(Element)所定義的接受操做接口。spa
5.ObjectStructure 結構對象角色,這是使用訪問者模式必備的角色。它具有如下特性:能枚舉它的元素;能夠提供一個高層接口以容許訪問者訪問它的元素;若有須要,能夠設計成一個複合對象或者一個彙集(如一個列表或無序集合)。設計
以商店的銷售記錄爲例,每條記錄記錄了所賣商品的名字、數量和價格,對於老闆這個訪問者關係的是總的銷售額,而對於採購員這個訪問者則關心的是各個商品的銷售數量。此時咱們就可使用訪問者模式,將數據操做與數據結構分離,從而使得不一樣的訪問者類針對對象結構來完成不一樣的操做。類圖以下:code
下面是簡單demo對象
package visitor; public abstract class Bill { abstract void accept(Visitor visitor); }
package visitor; public class SailBill extends Bill { private Long count; private Long price; private String name; public Long getCount() { return count; } public void setCount(Long count) { this.count = count; } public Long getPrice() { return price; } public void setPrice(Long price) { this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public void accept(Visitor visitor) { visitor.visitBill(this); } public SailBill(Long count, Long price, String name) { super(); this.count = count; this.price = price; this.name = name; } }
package visitor; public interface Visitor { void visitBill(SailBill bill); }
package visitor; public class Boss implements Visitor { private double income; @Override public void visitBill(SailBill bill) { income += bill.getCount()*bill.getPrice(); } public double getIncome() { return income; } public void setIncome(double income) { this.income = income; } }
package visitor; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; public class Buyer implements Visitor { private Map<String,Long> salesVolume = new HashMap<String, Long>(); @Override public void visitBill(SailBill bill) { if(salesVolume.get(bill.getName())==null) { salesVolume.put(bill.getName(), bill.getCount()); }else { salesVolume.put(bill.getName(), salesVolume.get(bill.getName()) + bill.getCount()); } } public void display() { for (Entry<String,Long> entry : salesVolume.entrySet()) { System.out.println(entry.getKey() +"-----" + entry.getValue()); } } }
package visitor; import java.util.ArrayList; import java.util.List; public class ObjectStructure { private List<Bill> list = new ArrayList<>(); public void addBill(Bill bill) { list.add(bill); } public void show (Visitor visitor) { for (Bill bill : list) { bill.accept(visitor); } } }
執行測試代碼以下blog
訪問者模式的使用場景:
一、 一個對象結構包含不少類對象,它們有不一樣的接口,而你想對這些對象實施一些依賴於其具體類的操做。
二、 須要對一個對象結構中的對象進行不少不一樣的而且不相關的操做,而你想避免讓這些操做「污染」這些對象的類。Visitor模式使得你能夠將相關的操做集中起來 定義在一個類
三、 當該對象結構被不少應用共享時,用Visitor模式讓每一個應用僅包含須要用到的操做。
四、定義對象結構的類不多改變,但常常須要在此結構上定義新的操做。改變對象結構類須要重定義對全部訪問者的接口,這可能須要很大的代價。若是對象結構類常常改變,那麼可能仍是在這些類中定義這些操做較好。