
Visitor 模式:把操作抽出來
Visitor 模式把對物件的操作集中到訪問者,讓你在不改動資料結構的情況下新增行為。
classDiagram class Element { <<abstract>> +accept(visitor)* void } class EmployeeData { -name : String -salary : Number -department : String +accept(visitor) void } class SalesData { -product : String -amount : Number -region : String +accept(visitor) void } class Visitor { <<interface>> +visitEmployee(employee)* void +visitSales(sales)* void } class ReportVisitor { -report : String[] +visitEmployee(employee) void +visitSales(sales) void +getReport() String } Element <|-- EmployeeData Element <|-- SalesData Visitor <|.. ReportVisitor Element ..> Visitor : accept(visitor)
使用情境
- 報告生成:訪問不同資料結構輸出不同報表。
- 資料分析:對各種資料節點進行統計。
- 檔案處理:依檔案類型套用不同操作。
實作範例

class Element {
accept(visitor) {
throw new Error('accept must be implemented');
}
}
class EmployeeData extends Element {
constructor(name, salary, department) {
super();
this.name = name;
this.salary = salary;
this.department = department;
}
accept(visitor) {
visitor.visitEmployee(this);
}
}
class SalesData extends Element {
constructor(product, amount, region) {
super();
this.product = product;
this.amount = amount;
this.region = region;
}
accept(visitor) {
visitor.visitSales(this);
}
}
class ReportVisitor {
constructor() {
this.report = [];
}
visitEmployee(employee) {
this.report.push(
`Employee: ${employee.name}, Department: ${employee.department}`
);
}
visitSales(sales) {
this.report.push(
`Sales: ${sales.product}, Amount: $${sales.amount}`
);
}
getReport() {
return this.report.join('\n');
}
}
const elements = [
new EmployeeData('John', 50000, 'Engineering'),
new EmployeeData('Jane', 60000, 'Marketing'),
new SalesData('Product A', 10000, 'Asia'),
];
const visitor = new ReportVisitor();
elements.forEach(element => element.accept(visitor));
console.log(visitor.getReport());優點
- 新增操作不需改動資料結構
- 操作集中管理
缺點
- 新增元素時要改訪問者
- 對私有成員存取受限