訪問者模式表示作用於物件結構中各元素的操作,讓您在不變更元素類別的前提下定義新操作,將資料結構與操作解耦。優點:新增操作容易(只需新增 Visitor),相關行為集中在訪問者物件中。
資料結構穩定、演算法易變時適用;若資料結構頻繁變動則不適合。
ConcreteElement 宣告 VisitVisit 方法Accept(Visitor) 遍歷Accept(Visitor)Accept 呼叫 visitor.VisitConcreteElementX(this)
// Visitor
public abstract class Visitor {
public abstract void VisitConcreteElementA(ConcreteElementA e);
public abstract void VisitConcreteElementB(ConcreteElementB e);
}
public class ConcreteVisitor1 : Visitor {
public override void VisitConcreteElementA(ConcreteElementA e) => Console.WriteLine($"{GetType().Name} 訪問 {e.GetType().Name}");
public override void VisitConcreteElementB(ConcreteElementB e) => Console.WriteLine($"{GetType().Name} 訪問 {e.GetType().Name}");
}
public class ConcreteVisitor2 : Visitor {
public override void VisitConcreteElementA(ConcreteElementA e) => Console.WriteLine($"{GetType().Name} 訪問 {e.GetType().Name}");
public override void VisitConcreteElementB(ConcreteElementB e) => Console.WriteLine($"{GetType().Name} 訪問 {e.GetType().Name}");
}
// Element
public abstract class Element { public abstract void Accept(Visitor v); }
public class ConcreteElementA : Element {
public override void Accept(Visitor v) => v.VisitConcreteElementA(this);
public void OperationA() { }
}
public class ConcreteElementB : Element {
public override void Accept(Visitor v) => v.VisitConcreteElementB(this);
public void OperationB() { }
}
// ObjectStructure
public class ObjectStructure {
List<Element> elements = new List<Element>();
public void Add(Element e) => elements.Add(e);
public void Remove(Element e) => elements.Remove(e);
public void Accept(Visitor v) => elements.ForEach(e => e.Accept(v));
}
// Client
static void Main() {
var os = new ObjectStructure();
os.Add(new ConcreteElementA()); os.Add(new ConcreteElementB());
os.Accept(new ConcreteVisitor1()); os.Accept(new ConcreteVisitor2());
}
element.Accept(visitor) → visitor.VisitConcreteElement(element),透過方法多載解析在編譯期確定具體元素類型,在執行期確定具體訪問者類型,實現雙重分派。
訪問者模式將演算法從資料結構分離,適合「資料結構固定、操作多變」場景(如編譯器 AST 遍歷、報表匯出、XML 處理),是實現開放封閉原則的有力工具。