定義
封裝一些作用于某種數據結構中的各元素的操作,它可以在不改變這個暑假結構的前提下定義作用于這些元素的新的操作
使用場景
- 對象結構比較穩定,但經常需要再此對象上定義新的操作
- 需要對一個對象結構中的對象進行很多不同的并且不想關的操作,而需要避免這些操作“污染”這些對象的類,也不希望在新增操作時修改這些類
結構
visitor 接口或抽象類
定義了對每一個元素訪問的行為,它的參數就是可以訪問的元素ConcreteVisitor 具體訪問者
給出每一個元素類訪問時產生的具體行為Element 元素接口或抽象接口
定義了一個接受訪問者的方法,其意義是指每個元素都要可以被訪問者訪問ElementA、ElementB 具體元素類
提供接受訪問者的具體實現ObjectStructure 定義當中所提到的對象結果
它內部管理了元素集合,并且可以迭代這些元素供訪問者訪問
簡單實現
public interface Visitor {
void visit(Engineer engineer);
void visit(Manager manager);
}
Visitor定義了一個visitor接口,有2個visit函數,對于Engineer、Manager的訪問會調用2個不同的方法,以此達到差異化處理
public abstract class Staff {
public String name;
public int kpi;
public Staff(String name) {
this.name = name;
kpi = new Random().nextInt(10);
}
public abstract void accept(Visitor visitor);
}
Staff為員工基類,定義了一個accept方法用來表示接受訪問者訪問,由子類具體實現
public class Manager extends Staff {
private int products;
public Manager(String name) {
super(name);
products = new Random().nextInt(10);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public int getProducts() {
return products;
}
}
Manager為經理類
public class Engineer extends Staff {
public Engineer(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* @return 工程師這一年的代碼數量
*/
public int getCodeLines() {
return new Random().nextInt(10 * 10000);
}
}
Engineer為工程師類
public class CTOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("工程師 :" + engineer.name + " , 代碼行數" + engineer.getCodeLines());
}
@Override
public void visit(Manager manager) {
System.out.println("經理 :" + manager.name + " ,新產品數量 :" + manager.getProducts());
}
}
CTOVisitor為CTO訪問者,關心技術貢獻
public class CEOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("工程師 :" + engineer.name + " , KPI" + engineer.kpi);
}
@Override
public void visit(Manager manager) {
System.out.println("經理 :" + manager.name + " , KPI" + manager.kpi + " ,新產品數量 :" + manager.getProducts());
}
}
CEOVisitor為CEO訪問者 只關注業績
public class BusinessReport {
List<Staff> mStaff = new LinkedList<>();
public BusinessReport() {
mStaff.add(new Manager("王經理"));
mStaff.add(new Engineer("工程師-Shawn.Xiong"));
mStaff.add(new Engineer("工程師-Kael"));
mStaff.add(new Engineer("工程師-Jack"));
mStaff.add(new Engineer("工程師-Rose"));
}
/**
* 為訪問者展示報表
* @param visitor
*/
public void showReport(Visitor visitor) {
for (Staff staff : mStaff) {
staff.accept(visitor);
}
}
}
BusinessReport為員工業務報表,訪問者可以通過showReport函數查看所有員工的業績
public class Client {
public static void main(String[] args) {
BusinessReport report = new BusinessReport();
System.out.println("---------- 給 CEO 看的報表 -------------");
report.showReport(new CEOVisitor());
System.out.println("\n---------- 給 CTO 看的報表 -------------");
report.showReport(new CTOVisitor());
}
}
運行結果:
---------- 給 CEO 看的報表 -------------
經理 :王經理 , KPI0 ,新產品數量 :3
工程師 :工程師-Shawn.Xiong , KPI6
工程師 :工程師-Kael , KPI4
工程師 :工程師-Jack , KPI1
工程師 :工程師-Rose , KPI2
---------- 給 CTO 看的報表 -------------
經理 :王經理 ,新產品數量 :3
工程師 :工程師-Shawn.Xiong , 代碼行數67720
工程師 :工程師-Kael , 代碼行數37258
工程師 :工程師-Jack , 代碼行數96044
工程師 :工程師-Rose , 代碼行數3708