訪問者模式(Visitor Pattern) 是一種將數據結構與數據操作分離的設計模式。是指封裝一
些作用於某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義作用於這些
元素的新的操作。屬於行爲型模式。
原文:Represent an operation to be performed on the elements of an object structure.Visitor lets you define a new operation without changing the classes of the elements on which it operates...o
訪問者模式被稱爲最複雜的設計模式,並且使用頻率不高,設計模式的作者也評價爲:大多
情況下,你不需要使用訪問者模式,但是一旦需要使用它時,那就真的需要使用了。訪問者模
式的基本思想是, 針對系統中擁有固定類型數的對象結構(元素) , 在其內提供一個accept()
方法用來接受訪問者對象的訪問。不同的訪問者對同一元素的訪問內容不同,使得相同的元素
集合可以產生不同的數據結果。accept() 方法可以接收不同的訪問者對象, 然後在內部將自己(元
素) 轉發到接收到的訪問者對象的visit() 方法內。訪問者內部對應類型的visit() 方法就會得到回
調執行, 對元素進行操作。也就是通過兩次動態分發(第一次是對訪問者的分發accept() 方法,
第二次是對元素的分發visit() 方法) , 才最終將一個具體的元素傳遞到一個具體的訪問者。如此
一來,就解耦了數據結構與操作,且數據操作不會改變元素狀態。
訪問者模式的核心是,解耦數據結構與數據操作,使得對元素的操作具備優秀的擴展性。可
以通過擴展不同的數據操作類型(訪問者)實現對相同元素集的不同的操作。
解耦數據結構和數據操作,
類比
食堂裏的座位,吃放工具,窗口(數據結構固定的), 進來吃飯的人就是訪問者他們來操作上面的數 據是不固定的,
kpi考覈 其組織方式是固定的(),查看kpi的人和被考查的人的方式是不固定的
類圖:
代碼:
訪問者接口
public interface IVisitor {
void visit(Engineer engineer);
void visit(Manager manager);
}
被考覈者的抽象類Employee
public abstract class Employee {
public String name;
public int kpi; //員工KPI
public Employee(String name) {
this.name = name;
kpi = new Random().nextInt(10);
}
//接收訪問者的訪問
public abstract void accept(IVisitor visitor);
}
被考覈者角色普通工程師Engineer
public class Engineer extends Employee {
public Engineer(String name) {
super(name);
}
public void accept(IVisitor visitor) {
visitor.visit(this);
}
//考覈指標是每年的代碼量
public int getCodeLines(){
return new Random().nextInt(10* 10000);
}
}
被考覈者角色產品經理Manager
public class Manager extends Employee {
public Manager(String name) {
super(name);
}
public void accept(IVisitor visitor) {
visitor.visit(this);
}
//考覈的是每年新產品研發數量
public int getProducts(){
return new Random().nextInt(10);
}
}
查看考覈成績的角色CEOVistitor
public class CEOVistitor implements IVisitor {
public void visit(Engineer engineer) {
System.out.println("工程師" + engineer.name + ",KIP:" + engineer.kpi);
}
public void visit(Manager manager) {
System.out.println("經理:" + manager.name + ",KPI:" + manager.kpi + ",產品數量:" + manager.getProducts());
}
}
查看考覈成績的角色CTOVistitor
public class CTOVistitor implements IVisitor {
public void visit(Engineer engineer) {
System.out.println("工程師" + engineer.name + ",代碼行數:" + engineer.getCodeLines());
}
public void visit(Manager manager) {
System.out.println("經理:" + manager.name + ",產品數量:" + manager.getProducts());
}
}
報表的方法BusinessReport
public class BusinessReport {
private List<Employee> employees = new LinkedList<Employee>();
public BusinessReport() {
employees.add(new Manager("產品經理A"));
employees.add(new Engineer("程序員A"));
employees.add(new Engineer("程序員B"));
employees.add(new Engineer("程序員C"));
employees.add(new Manager("產品經理B"));
employees.add(new Engineer("程序員D"));
}
public void showReport(IVisitor visitor){
for (Employee employee : employees) {
employee.accept(visitor);
}
}
}
測試方法:
public class Test {
public static void main(String[] args) {
BusinessReport report = new BusinessReport();
System.out.println("==========CEO看報表===============");
report.showReport(new CEOVistitor());
System.out.println("==========CTO看報表===============");
report.showReport(new CTOVistitor());
}
}
測試結果: