2013年11月27日 星期三

Design Pattern : Visitor

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);
}


2.  Visitor :
=>只提供一個訪問的方法,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);
}

接下來開始實做類別的部分

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;
     }
}


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));
    }
}

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);
  }
}


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


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 :
客戶(小叮噹),業代(二十一世紀車商)


8.  延伸閱讀:
StrategyVisitor

沒有留言:

張貼留言