Design Pattern : Visitor
Definition :
「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」
乍看之下和Strategy模式很像,可以參考後面的延伸閱讀。
1.
Element : 可存放要處理的物件或參數,再由外部帶入一個Visitor。 處理的方法是實作在Visitor。
2.
ObjectStructure:存放Element集合,提供新增、刪除元素,以及讓Client呼叫處理元素的方法。
3.
Visitor:提供方法注入於Element中做處理。
底下的程式碼為利用Visitor模式,對多台車子做試開、列出車子型號、列出訂車細節等不同的處理。
1.
Element:
=> 須由外部帶入一個Visitor
public interface IElement:IDisposable
{
void Accept<T>(IVisitor<T> visitor);
}
=> 須由外部帶入一個Visitor
public interface IElement:IDisposable
{
void Accept<T>(IVisitor<T> visitor);
}
2.
Visitor
:
=>只提供一個訪問的方法,obj 為訪問中所需要的物件。
public abstract class Visitor<T>
{
public abstract void Visit(T obj); //T is element
}
=>只提供一個訪問的方法,obj 為訪問中所需要的物件。
public abstract class Visitor<T>
{
public abstract void Visit(T obj); //T is element
}
3.
ObjectStructure:
public interface IObjectStructure<T>
{
List<IElement> Elements { get; set; }
void Attach(IElement element);
void Detach(IElement element);
void Accept(IVisitor<T> visitor);
}
接下來開始實做類別的部分…
public interface IObjectStructure<T>
{
List<IElement> Elements { get; set; }
void Attach(IElement element);
void Detach(IElement element);
void Accept(IVisitor<T> visitor);
}
接下來開始實做類別的部分…
4.
定義兩種Element :
=> _car物件是要帶給Visitor的參數。
public class CarElement : IElement
{
private ICar _car = null;
public CarElement(ICar car)
{
this._car = car;
}
public void Accept<T>(IVisitor<T> visitor)
{
visitor.Visit((T)this._car);
}
public void Dispose()
{
this._car = null;
}
}
public class CarMidRangeElement:IElement
{
ICarMidRange _car = null;
public CarMidRangeElement(ICarMidRange car)
{
this._car = car;
}
public void Accept<T>(IVisitor<T> visitor)
{
visitor.Visit((T)this._car);
}
public void Dispose()
{
this._car = null;
}
}
=> _car物件是要帶給Visitor的參數。
public class CarElement : IElement
{
private ICar _car = null;
public CarElement(ICar car)
{
this._car = car;
}
public void Accept<T>(IVisitor<T> visitor)
{
visitor.Visit((T)this._car);
}
public void Dispose()
{
this._car = null;
}
}
public class CarMidRangeElement:IElement
{
ICarMidRange _car = null;
public CarMidRangeElement(ICarMidRange car)
{
this._car = car;
}
public void Accept<T>(IVisitor<T> visitor)
{
visitor.Visit((T)this._car);
}
public void Dispose()
{
this._car = null;
}
}
5.
CarObjectStructure :
=>提供存放Element的容器。
=>提供可以Visit每個Element的方法。
public class CarObjectStructure<T> : IObjectStructure<T>
{
public List<IElement> Elements { get; set; }
public CarObjectStructure()
{
this.Elements = new List<IElement>();
}
public void Attach(IElement element)
{
this.Elements.Add(element);
}
public void Detach(IElement element)
{
this.Elements.Remove(element);
}
public void Accept(IVisitor<T> visitor)
{
this.Elements.ForEach(x => x.Accept<T>(visitor));
}
}
=>提供存放Element的容器。
=>提供可以Visit每個Element的方法。
public class CarObjectStructure<T> : IObjectStructure<T>
{
public List<IElement> Elements { get; set; }
public CarObjectStructure()
{
this.Elements = new List<IElement>();
}
public void Attach(IElement element)
{
this.Elements.Add(element);
}
public void Detach(IElement element)
{
this.Elements.Remove(element);
}
public void Accept(IVisitor<T> visitor)
{
this.Elements.ForEach(x => x.Accept<T>(visitor));
}
}
6.
Visitor
: visitor可以提供business邏輯供注入,這邊實做了三種visitor:
/// 試乘
public class DriveVisitor<T>:Visitor<T>
{
public override void Visit(T obj)
{
(obj as ICar).Drive();
}
}
/// 列出車子型號
public class ListNameVisitor<T> : Visitor<T>
{
public override void Visit(T obj)
{
Console.WriteLine((obj as ICar).Name);
}
}
/// 列出ICarMidRange車子的資訊
public class InfoVisitor<T> : Visitor<T>
{
public override void Visit(T obj)
{
var midCar = (obj as ICarMidRange);
Console.WriteLine("{0} : 客戶({1}),業代({2})",
midCar.Name, midCar.CustomerName, midCar.SalesName);
}
}
/// 試乘
public class DriveVisitor<T>:Visitor<T>
{
public override void Visit(T obj)
{
(obj as ICar).Drive();
}
}
/// 列出車子型號
public class ListNameVisitor<T> : Visitor<T>
{
public override void Visit(T obj)
{
Console.WriteLine((obj as ICar).Name);
}
}
/// 列出ICarMidRange車子的資訊
public class InfoVisitor<T> : Visitor<T>
{
public override void Visit(T obj)
{
var midCar = (obj as ICarMidRange);
Console.WriteLine("{0} : 客戶({1}),業代({2})",
midCar.Name, midCar.CustomerName, midCar.SalesName);
}
}
7.
主程式:
u
#region Element帶入ICar物件,存入CarObjectStructure,再利用visitor處理邏輯
ICar focus = new Focus();
ICar civic = new Civic();
//建立ObjectStructure並放入Element
IObjectStructure<ICar> carStruct = new CarObjectStructure<ICar>();
carStruct.Attach(new CarElement(focus));
carStruct.Attach(new CarElement(civic));
//利用DriveVisitor對每個Element處理邏輯
IVisitor<ICar> visitor1 = new DriveVisitor<ICar>();
carStruct.Accept(visitor1);
//利用ListNameVisitor對每個Element處理邏輯
IVisitor<ICar> visitor2 = new ListNameVisitor<ICar>();
carStruct.Accept(visitor2);
carStruct = null;
#endregion
結果:
I am driving Black Focus(FORD)
I am driving Black Civic(HONDA)
Focus
Civic
#region Element帶入ICar物件,存入CarObjectStructure,再利用visitor處理邏輯
ICar focus = new Focus();
ICar civic = new Civic();
//建立ObjectStructure並放入Element
IObjectStructure<ICar> carStruct = new CarObjectStructure<ICar>();
carStruct.Attach(new CarElement(focus));
carStruct.Attach(new CarElement(civic));
//利用DriveVisitor對每個Element處理邏輯
IVisitor<ICar> visitor1 = new DriveVisitor<ICar>();
carStruct.Accept(visitor1);
//利用ListNameVisitor對每個Element處理邏輯
IVisitor<ICar> visitor2 = new ListNameVisitor<ICar>();
carStruct.Accept(visitor2);
carStruct = null;
#endregion
結果:
I am driving Black Focus(FORD)
I am driving Black Civic(HONDA)
Focus
Civic
u #region Element帶入ICarMidRange物件,存入CarObjectStructure,再利用visitor處理邏輯
ICarMidRange is300h = new Is300h();
is300h.CustomerName = "小叮噹";
is300h.SalesName = "二十一世紀車商";
//建立ObjectStructure並放入Element
IObjectStructure<ICarMidRange> carMidStruct = new CarObjectStructure<ICarMidRange>();
carMidStruct.Attach(new CarMidRangeElement(is300h));
//利用DriveVisitor對每個Element處理邏輯
IVisitor<ICarMidRange> visitor3 = new DriveVisitor<ICarMidRange>();
carMidStruct.Accept(visitor3);
//利用InfoVisitor對每個Element處理邏輯
IVisitor<ICarMidRange> visitor4 = new InfoVisitor<ICarMidRange>();
carMidStruct.Accept(visitor4);
carMidStruct = null;
#endregion
結果:
I am driving Black Is300h(Lexxx)
Is300h : 客戶(小叮噹),業代(二十一世紀車商)
ICarMidRange is300h = new Is300h();
is300h.CustomerName = "小叮噹";
is300h.SalesName = "二十一世紀車商";
//建立ObjectStructure並放入Element
IObjectStructure<ICarMidRange> carMidStruct = new CarObjectStructure<ICarMidRange>();
carMidStruct.Attach(new CarMidRangeElement(is300h));
//利用DriveVisitor對每個Element處理邏輯
IVisitor<ICarMidRange> visitor3 = new DriveVisitor<ICarMidRange>();
carMidStruct.Accept(visitor3);
//利用InfoVisitor對每個Element處理邏輯
IVisitor<ICarMidRange> visitor4 = new InfoVisitor<ICarMidRange>();
carMidStruct.Accept(visitor4);
carMidStruct = null;
#endregion
結果:
I am driving Black Is300h(Lexxx)
Is300h : 客戶(小叮噹),業代(二十一世紀車商)
沒有留言:
張貼留言