設計模式-行為型-訪問者模式

  • 2019 年 10 月 10 日
  • 筆記

訪問者模式(Vistor):

  訪問者模式的官方定義是這樣的:表示一個作用於某對象結構中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用於這些元素的新操作。官方的東西總是晦澀難懂的,那麼我們現在就來拆解一下:首先”一個作用於某對象結構中的各元素的操作”,提到了三個東西:對象結構、元素、操作。我們都學習過數據結構,數據結構中大家對數據的訪問一般都是直接訪問其地址。在面向對象的設計中,我們一般也是將數據的訪問操作放在類的內部,便於訪問。這種設計看似沒有什麼問題,但當我們想要採用不同方式訪問數據或對象結構時就必須要對類進行修改,這樣就違反了OCP原則。於是大家會想到將數據結構與操作分離開來,當問們需要添加訪問操作的時候直接添加新的類,原來的程式碼不需要做任何改變,這也是後半句提到的”可以在不改變各元素類的前提下定義作用於這些元素的新操作”。

訪問者模式的角色:

  

  1)Visitor:介面或抽象類,定義了對每個Element訪問的行為,它的參數就是被訪問的元素,它的方法個數理論上與元素的個數是一樣的,因此,訪問者模式要求元素的類型要穩定,如果經常添加、移除元素類,必然會導致頻繁地修改visitor介面,如果出現這種情況,則說明不適合使用該模式。

  2)ConcreteVisitor:具體的訪問者,它需要給出對每一個元素類訪問時所產生的具體行為。

  3)Element:元素介面或抽象類,它定義了一個接受訪問者的方法(accept),其意思就是說每一個元素都可以被訪問者訪問。

  4)ConcreteElement:具體的元素類,它提供接受訪問的具體實現,而這個具體實現通常情況下是使用訪問者提供的訪問該元素類的方法。

  5)ObjectStructure:定義當中所提到的對象結構,對象結構是一個抽象表述,它內部管理了元素集合,並且可以迭代這些元素提供訪問者訪問。

示例:

  一個目錄下面有文件夾和文件,文件夾和文件是具體的元素類。 

 1 /// <summary>   2 /// 抽象訪問者   3 /// </summary>   4 public abstract class Visitor   5 {   6     public abstract void visit(File file);   7   8     public abstract void visit(Directory directory);   9 }  10  11 /// <summary>  12 /// 具體的訪問者  13 /// </summary>  14 public class ListVisitor : Visitor  15 {  16     public override void visit(File file)  17     {  18         Console.WriteLine($"文件名稱{file.GetName()}");  19     }  20  21     public override void visit(Directory directory)  22     {  23         Console.WriteLine($"文件夾名稱{directory.GetName()}");  24     }  25 }  26  27 /// <summary>  28 /// 元素抽象類  29 /// </summary>  30 public abstract class Element  31 {  32     public abstract void accept(Visitor visitor);  33 }  34  35 public class Entry : Element  36 {  37     private string name;  38  39     public Entry(string name)  40     {  41         this.name = name;  42     }  43  44     public string GetName()  45     {  46         return this.name;  47     }  48  49     public override void accept(Visitor visitor)  50     {  51         throw new NotImplementedException();  52     }  53 }  54  55 /// <summary>  56 /// 具體的元素類:文件夾  57 /// </summary>  58 public class Directory : Entry  59 {  60     public Directory(string name)  61         : base(name)  62     {  63     }  64  65     public override void accept(Visitor visitor)  66     {  67         visitor.visit(this);  68     }  69 }  70  71 /// <summary>  72 /// 具體的元素類:文件  73 /// </summary>  74 public class File : Entry  75 {  76     public File(string name)  77         : base(name)  78     {  79     }  80  81     public override void accept(Visitor visitor)  82     {  83         visitor.visit(this);  84     }  85 }

  定義好了,數據操作,接下來我們定義數據結構的核心類ObjectStructure。

 1 public class ObjectStructure   2 {   3     private readonly Visitor visitor;   4     private List<Element> list = new List<Element>();   5   6     public ObjectStructure(Visitor visitor)   7     {   8         this.visitor = visitor;   9     }  10  11     public void Add(Element element)  12     {  13         list.Add(element);  14     }  15  16     public void Show()  17     {  18         foreach (Element element in list)  19         {  20             element.accept(visitor);  21         }  22     }  23 }

  客戶端調用。

 1 private static void Main(string[] args)   2 {   3     ObjectStructure objectStructure = new ObjectStructure(new ListVisitor());   4     objectStructure.Add(new Directory("我的文件夾"));   5     objectStructure.Add(new File("C#高級編程.pdf"));   6     objectStructure.Add(new File("設計模式.pdf"));   7     objectStructure.Add(new File("演算法.txt"));   8     objectStructure.Add(new File("mm.png"));   9     objectStructure.Show();  10 }

訪問者模式的優缺點:

  優點:

    1)各角色職責分離,符合單一職責原則

    2)具有優秀的擴展性,使得數據結構和作用於結構上的操作解耦,使得操作集合可以獨立變化。

    3)靈活性

  缺點:

    1)具體元素對訪問者公布細節,違反了迪米特原則

    2)具體元素變更比較困難。 

    3)違反了依賴倒置原則,依賴了具體類,沒有依賴抽象。

訪問者模式的使用場景:

  1)對象結構中對象對應的類很少改變,但經常需要在此對象結構上定義新的操作。

  2)需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而需要避免讓這些操作”污染”這些對象的類,也不希望在增加新操作時修改這些類。  

參考:https://www.cnblogs.com/zyrblog/p/9244754.html