標籤:訪問 png 集中 回調 ons 資料 表示 attach 標識
訪問者模式
在GOF的《設計模式:可複用物件導向軟體的基礎》一書中對訪問者模式是這樣說的:表示一個作用於某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。訪問者模式把資料結構和作用於結構上的操作之間的耦合解脫開,使得操作集合可以相對自由地演化。該模式的目的是要把處理從資料結構分離出來。訪問者模式讓增加新的操作很容易,因為增加新的操作就意味著增加一個新的訪問者。訪問者模式將有關的行為集中到一個訪問者對象中。現在再來說說我之前經曆過的那個項目。
是基於Windows Shell開發的一個項目,在一個容器中儲存了很多的Shell Items,同時定義了對Items的操作,由於項目一直都在進行後期擴充,對Items的操作在後期都需要進行擴充的;而現在的做法是,定義一個操作類,該操作類中定義了一個集合,該集合存放Items,在該操作類中擴充對應的操作方法。現在想想如果使用訪問者模式也是可以的,由於Items集合是固定的,當需要擴充集合的操作時,只需要添加對應的訪問者即可。
UML類圖
Visitor(訪問者):為該對象結構中ConcreteElement的每一個類聲明一個Visit操作。該操作的名字和特徵標識了發送Visit請求給該訪問者的那個類。這使得訪問者可以確定正被訪問元素的具體的類。這樣訪問者就可以通過該元素的特定介面直接存取它。
ConcreteVisitor(具體訪問者):實現每個由Visitor聲明的操作。每個操作實現本演算法的一部分,而該演算法片段乃是對應於結構中對象的類。ConcreteVisitor為該演算法提供了上下文並儲存它的局部狀態。這一狀態常常在遍曆該結構的過程中累積結果。
Element(元素):定義一個Accept操作,它以一個訪問者為參數。
ConcreteElement(具體元素):實現Accept操作,該操作以一個訪問者為參數。
ObjectStructure(對象結構):能夠枚舉它的元素,同時提供一個高層的介面以允許該訪問者訪問它的元素。
使用場合
- 一個對象結構包含很多類對象,它們有不同的介面,而你想對這些對象實施一些依賴於其具體類的操作;
- 需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而你想避免讓這些操作“汙染”這些對象的類。Visitor使得你可以將相關的操作集中起來定義在一個類中;
- 當該對象結構被很多應用共用時,用Visitor模式讓每個應用僅包含需要用到的操作;
- 定義對象結構的類很少改變,但經常需要在此結構上定義新的操作。改變對象結構類需要重定義對所有訪問者的介面,這可能需要很大的代價。如果對象結構類經常改變,那麼可能還是在這些類中定義這些操作較好。
代碼實現
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 class ConcreteElementA; 6 class ConcreteElementB; 7 8 class Visitor 9 { 10 public: 11 virtual void VisitConcreteElementA(ConcreteElementA *pElementA) = 0; 12 virtual void VisitConcreteElementB(ConcreteElementB *pElementB) = 0; 13 }; 14 15 class ConcreteVisitor1 : public Visitor 16 { 17 public: 18 void VisitConcreteElementA(ConcreteElementA *pElementA); 19 void VisitConcreteElementB(ConcreteElementB *pElementB); 20 }; 21 22 void ConcreteVisitor1::VisitConcreteElementA(ConcreteElementA *pElementA) 23 { 24 // 現在根據傳進來的pElementA,可以對ConcreteElementA中的element進行操作 25 } 26 27 void ConcreteVisitor1::VisitConcreteElementB(ConcreteElementB *pElementB) 28 { 29 // 現在根據傳進來的pElementB,可以對ConcreteElementB中的element進行操作 30 } 31 32 class ConcreteVisitor2 : public Visitor 33 { 34 public: 35 void VisitConcreteElementA(ConcreteElementA *pElementA); 36 void VisitConcreteElementB(ConcreteElementB *pElementB); 37 }; 38 39 void ConcreteVisitor2::VisitConcreteElementA(ConcreteElementA *pElementA) 40 { 41 // ... 42 } 43 44 void ConcreteVisitor2::VisitConcreteElementB(ConcreteElementB *pElementB) 45 { 46 // ... 47 } 48 49 // Element object 50 class Element 51 { 52 public: 53 virtual void Accept(Visitor *pVisitor) = 0; 54 }; 55 56 class ConcreteElementA : public Element 57 { 58 public: 59 void Accept(Visitor *pVisitor); 60 }; 61 62 void ConcreteElementA::Accept(Visitor *pVisitor) 63 { 64 pVisitor->VisitConcreteElementA(this); 65 } 66 67 class ConcreteElementB : public Element 68 { 69 public: 70 void Accept(Visitor *pVisitor); 71 }; 72 73 void ConcreteElementB::Accept(Visitor *pVisitor) 74 { 75 pVisitor->VisitConcreteElementB(this); 76 } 77 78 // ObjectStructure類,能枚舉它的元素,可以提供一個高層的介面以允許訪問者訪問它的元素 79 class ObjectStructure 80 { 81 public: 82 void Attach(Element *pElement); 83 void Detach(Element *pElement); 84 void Accept(Visitor *pVisitor); 85 86 private: 87 vector<Element *> elements; 88 }; 89 90 void ObjectStructure::Attach(Element *pElement) 91 { 92 elements.push_back(pElement); 93 } 94 95 void ObjectStructure::Detach(Element *pElement) 96 { 97 vector<Element *>::iterator it = find(elements.begin(), elements.end(), pElement); 98 if (it != elements.end()) 99 {100 elements.erase(it);101 }102 }103 104 void ObjectStructure::Accept(Visitor *pVisitor)105 {106 // 為每一個element設定visitor,進行對應的操作107 for (vector<Element *>::const_iterator it = elements.begin(); it != elements.end(); ++it)108 {109 (*it)->Accept(pVisitor);110 }111 }112 113 int main()114 {115 ObjectStructure *pObject = new ObjectStructure;116 117 ConcreteElementA *pElementA = new ConcreteElementA;118 ConcreteElementB *pElementB = new ConcreteElementB;119 120 pObject->Attach(pElementA);121 pObject->Attach(pElementB);122 123 ConcreteVisitor1 *pVisitor1 = new ConcreteVisitor1;124 ConcreteVisitor2 *pVisitor2 = new ConcreteVisitor2;125 126 pObject->Accept(pVisitor1);127 pObject->Accept(pVisitor2);128 129 if (pVisitor2) delete pVisitor2;130 if (pVisitor1) delete pVisitor1;131 if (pElementB) delete pElementB;132 if (pElementA) delete pElementA;133 if (pObject) delete pObject;134 135 return 0;136 }
總結
訪問者模式的基本思想如下:首先擁有一個由許多個物件構成的對象結構,就是上面代碼中的ObjectStructure,這些對象的類都擁有一個Accept方法用來接受訪問者對象;訪問者是一個介面,它擁有一個Visit方法,這個方法對訪問到的對象結構中不同類型的元素做出不同的操作;在對象結構的一次訪問過程中,我們遍曆整個對象結構,對每一個元素都實施Accept方法,在每一個元素的Accept方法中回調訪問者的Visit方法,從而使訪問者得以處理對象結構的每一個元素。我們就可以針對對象結構設計不同的訪問者類來完成不同的操作。
設計模式中經常說的一句話是:發現變化並封裝之。是否採用訪問者模式,就要看“變化”是什麼。訪問者模式中,“變化”是具體訪問者,其次是對象結構;但是,如果具體元素也會發生改變,就萬萬不能使用訪問者模式,因為這樣“牽一髮而動全身”,後期的維護性就太差了。
C++設計模式——訪問者模式