說明:
當一個「物件結構」中的「元素」幾乎不會異動,但這些「元素的行為」常會增減,則適合用訪問者模式。
訪問者模式是將「元素的行為」,提取出來,每一種行為做成一個 「Visitor(訪問者) 物件」,
每一個 「Visitor(訪問者) 物件」,都能依據不同的「元素」,對應到不同的行為結果。
範例:
在一個遊戲結構中,有兩種人,誠實人、說謊人。
誠實人都說真話,說謊人都說假話。
誠實人、說謊人即是不會異動的元素,
但對誠實人、說謊人「提出的問題」,是可能會改變的,
所以「提出的問題」即可當作「Visitor(訪問者) 物件」,用訪問者模式 (Visitor Pattern),對以後要增減「提出的問題」是較方便的。
(但若要新增第三種人則較麻煩)
希望達成如下的效果
static void Main(string[] args)
{
// 物件結構
ObjectStructure o = new ObjectStructure();
// 誠實人元素物件
HonestManElement honestMan = new HonestManElement();
// 說謊人元素物件
LieManElement lieMan = new LieManElement();
// 將誠實人、說謊人元素物件放進物件結構
o.Attach(honestMan);
o.Attach(lieMan);
// 數學問題訪問者
MathVisitor mathVisitor = new MathVisitor();
Console.WriteLine("[數學問題]");
o.Display(mathVisitor); // 輸出結果
// 物理問題訪問者
PhysicsVisitor physicsVisitor = new PhysicsVisitor();
Console.WriteLine("[物理問題]");
o.Display(physicsVisitor); // 輸出結果
Console.Read();
}
執行結果:[數學問題] 誠實人 說: 1+1=2 說謊人 說: 1+1=3 [物理問題] 誠實人 說: 鐵球在水中會沉下去 說謊人 說: 鐵球在水中會浮起來
實現的重點在於,物件往返傳了兩次,
第一次是「Visitor物件」經由「結構物件」傳給「元素物件」
第二次是「元素物件」將自己傳給「Visitor物件」,以便「Visitor物件」依不同的「元素物件」執行不同的方法。
其餘程式碼
// 物件結構
class ObjectStructure
{
private List<Element> elements = new List<Element>();
//增加元素物件
public void Attach(Element element)
{
elements.Add(element);
}
//移除元素物件
public void Detach(Element element)
{
elements.Remove(element);
}
//顯示
public void Display(Visitor visitor)
{
foreach (Element e in elements)
{
e.Accept(visitor);
}
}
}
// 元素抽像類別 (要放入物件結構中)
abstract class Element
{
// 每個元素要能接收訪問者物件,以便再將自己傳給訪問者
public abstract void Accept(Visitor visitor);
}
// 誠實人元素物件
class HonestManElement : Element
{
public string name = "誠實人";
public override void Accept(Visitor visitor)
{
// 將自己傳給訪問者,以便訪問者分辨、執行適合自己的行為
visitor.visit(this);
}
}
// 說謊人元素物件
class LieManElement : Element
{
public string name = "說謊人";
public override void Accept(Visitor visitor)
{
// 將自己傳給訪問者,以便訪問者分辨、執行適合自己的行為
visitor.visit(this);
}
}
// 訪問者 (能根據不同元素,產生不同結果)
abstract class Visitor
{
// 訪問誠實人的多載方法
public abstract void visit(HonestManElement honestElement);
// 訪問說謊人的多載方法
public abstract void visit(LieManElement lieElement);
}
// 數學問題訪問者
class MathVisitor : Visitor
{
// 訪問誠實人的多載方法
public override void visit(HonestManElement honestElement)
{
Console.WriteLine("{0} 說: 1+1=2", honestElement.name);
}
// 訪問說謊人的多載方法
public override void visit(LieManElement lieElement)
{
Console.WriteLine("{0} 說: 1+1=3", lieElement.name);
}
}
// 物理問題訪問者
class PhysicsVisitor : Visitor
{
// 訪問誠實人的多載方法
public override void visit(HonestManElement honestElement)
{
Console.WriteLine("{0} 說: 鐵球在水中會沉下去", honestElement.name);
}
// 訪問說謊人的多載方法
public override void visit(LieManElement lieElement)
{
Console.WriteLine("{0} 說: 鐵球在水中會浮起來", lieElement.name);
}
}
相關連結:設計模式整理列表
沒有留言:
張貼留言