由于應用開發程序中先前完成的型別會因為需求變化(無論是業務功能,還是技術實作或是出于集成的需要)增加新的方法,如果直接在基類中增加新的方法,其派生型別可能需要相應進行比較繁瑣的處理,而使用訪問者模式可以做到在不改變既有型別層次的前提下,運行時動態為型別層次的每個類增加新的操作,
訪問者模式
GOF對策略模式的描述為:
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...
— Design Patterns : Elements of Reusable Object-Oriented Software
UML類圖

訪問者模式包含五種角色:
- IVistor(抽象訪問者):為該物件結構中具體元素角色宣告一個訪問操作介面,
- ConcreteVisitor(具體訪問者):每個具體訪問者都實作了IVistor中定義的操作,
- IElement(抽象元素):定義了一個accept操作,以IVisitor作為引數,
- ConcreteElement(具體元素):實作了IElement中的accept()方法,呼叫IVistor的訪問方法以便完成對一個元素的操作,
- ObjectStructure(物件結構):可以是組合模式,也可以是集合,能夠列舉它包含的元素,并提供一個介面,允許IVistor訪問它的元素,
代碼示例
設想有這樣一個HR系統,系統只能按照標準的作業時間、時薪計算薪金,在系統交付后發現需要提供加班計算功能,而且還需要安排休假、晉升等功能,考慮到類似的需求在將來還會出現,所以改造的時候考慮采用訪問者模式,在HR系統的物件上增加了Accept某個IVisistor介面的能力,在添加新功能的時候可以實作IVisitor介面,
public interface IEmployee
{
string Name { get; set; }
double Income { get; set; }
int VacationDays { get; set; }
void Accept(IVisitor visitor);
}
public interface IVisitor
{
void VisitiEmployee(IEmployee employee);
void VisitManager(Manager manager);
}
public class Employee : IEmployee
{
public string Name { get; set; }
public double Income { get; set; }
public int VacationDays { get; set; }
public Employee(string name, double income, int vacationDays)
{
this.Name = name;
this.Income = income;
this.VacationDays = vacationDays;
}
public void Accept(IVisitor visitor)
{
visitor.VisitiEmployee(this);
}
}
public class Manager : IEmployee
{
public string Department { get; set; }
public string Name { get; set; }
public double Income { get; set; }
public int VacationDays { get; set; }
public Manager(string name, double income, int vacationDays, string department)
{
this.Name = name;
this.Income = income;
this.VacationDays = vacationDays;
this.Department = department;
}
public void Accept(IVisitor visitor)
{
visitor.VisitManager(this);
}
}
public class EmployeeCollection : List<IEmployee>
{
public void Accept(IVisitor visitor)
{
foreach (IEmployee employee in this)
{
employee.Accept(visitor);
}
}
}
public class ExtraVacationVisitor : IVisitor
{
public void VisitiEmployee(IEmployee employee)
{
employee.VacationDays += 1;
}
public void VisitManager(Manager manager)
{
manager.VacationDays += 2;
}
}
public class RaiseSalaryVisitor : IVisitor
{
public void VisitiEmployee(IEmployee employee)
{
employee.Income *= 1.1;
}
public void VisitManager(Manager manager)
{
manager.Income *= 1.2;
}
}
呼叫端代碼
public class Test
{
public static void Entry()
{
EmployeeCollection employees = new EmployeeCollection();
employees.Add(new Employee("joe", 25000, 14));
employees.Add(new Manager("alice", 22000, 14, "sales"));
employees.Add(new Employee("peter", 15000, 7));
employees.Accept(new ExtraVacationVisitor());
employees.Accept(new RaiseSalaryVisitor());
}
}
Employee型別并沒有加薪和修改休假天數的方法,但借助訪問者模式,時期具有了對應的功能,訪問者模式的關鍵代碼是在資料基礎類里面有一個方法接受訪問者,將自身參考傳入訪問者,這樣訪問者就可以操作資料類了,
訪問者模式的適用場景
- 一個型別需要依賴于很多不同介面的型別,在結構盡量松散的前提下,希望可以用到這些型別不同介面方法,
- 經常需要為一個結構相對固定的物件結構添加一些新的操作,
- 需要用一個獨立的型別來組織一批不相干的操作,使用它的型別可以根據應用需要進行定制,
訪問者模式的特點
優點
- 符合單一職責原則,
- 優秀的擴展性,
- 靈活性,
缺點 - 具體元素對訪問者公布細節,違反了迪米特原則,
- 具體元素變更比較困難,
- 違反了依賴倒置原則,依賴了具體類,而不是依賴抽象,
參考書籍:
王翔著 《設計模式——基于C#的工程化實作及擴展》
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/122077.html
標籤:其他
上一篇:設計模式(23) 訪問者模式
