天天看點

C#設計模式(22)——通路者模式(Vistor Pattern)一、引言二、通路者模式介紹三、通路者模式的應用場景四、通路者模式的優缺點 五、總結

  在上一篇博文中分享了責任鍊模式,責任鍊模式主要應用在系統中的某些功能需要多個對象參與才能完成的場景。在這篇博文中,我将為大家分享我對通路者模式的了解。

   通路者模式是封裝一些施加于某種資料結構之上的操作。一旦這些操作需要修改的話,接受這個操作的資料結構則可以儲存不變。通路者模式适用于資料結構相對穩定的系統, 它把資料結構和作用于資料結構之上的操作之間的耦合度降低,使得操作集合可以相對自由地改變。

  資料結構的每一個節點都可以接受一個通路者的調用,此節點向通路者對象傳入節點對象,而通路者對象則反過來執行節點對象的操作。這樣的過程叫做“雙重分派”。節點調用通路者,将它自己傳入,通路者則将某算法針對此節點執行。

   從上面描述可知,通路者模式是用來封裝某種資料結構中的方法。具體封裝過程是:每個元素接受一個通路者的調用,每個元素的Accept方法接受通路者對象作為參數傳入,通路者對象則反過來調用元素對象的操作。具體的通路者模式結構圖如下所示。

C#設計模式(22)——通路者模式(Vistor Pattern)一、引言二、通路者模式介紹三、通路者模式的應用場景四、通路者模式的優缺點 五、總結

  這裡需要明确一點:通路者模式中具體通路者的數目和具體節點的數目沒有任何關系。從通路者的結構圖可以看出,通路者模式涉及以下幾類角色。

抽象通路者角色(Vistor):聲明一個活多個通路操作,使得所有具體通路者必須實作的接口。

具體通路者角色(ConcreteVistor):實作抽象通路者角色中所有聲明的接口。

抽象節點角色(Element):聲明一個接受操作,接受一個通路者對象作為參數。

具體節點角色(ConcreteElement):實作抽象元素所規定的接受操作。

結構對象角色(ObjectStructure):節點的容器,可以包含多個不同類或接口的容器。

   在講訴通路者模式的實作時,我想先不用通路者模式的方式來實作某個場景。具體場景是——現在我想周遊每個元素對象,然後調用每個元素對象的Print方法來列印該元素對象的資訊。如果此時不采用通路者模式的話,實作這個場景再簡單不過了,具體實作代碼如下所示:

  上面代碼很準确了解決了我們剛才提出的場景,但是需求在時刻變化的,如果此時,我除了想列印元素的資訊外,還想列印出元素被通路的時間,此時我們就不得不去修改每個元素的Print方法,再加入相對應的輸入通路時間的輸出資訊。這樣的設計顯然不符合“開-閉”原則,即某個方法操作的改變,會使得必須去更改每個元素類。既然,這裡變化的點是操作的改變,而每個元素的資料結構是不變的。是以此時就思考——能不能把操作于元素的操作和元素本身的資料結構分開呢?解開這兩者的耦合度,這樣如果是操作發現變化時,就不需要去更改元素本身了,但是如果是元素資料結構發現變化,例如,添加了某個字段,這樣就不得不去修改元素類了。此時,我們可以使用通路者模式來解決這個問題,即把作用于具體元素的操作由通路者對象來調用。具體的實作代碼如下所示:

  從上面代碼可知,使用通路者模式實作上面場景後,元素Print方法的通路封裝到了通路者對象中了(我覺得可以把Print方法封裝到具體通路者對象中。),此時用戶端與元素的Print方法就隔離開了。此時,如果需要添加列印通路時間的需求時,此時隻需要再添加一個具體的通路者類即可。此時就不需要去修改元素中的Print()方法了。

   每個設計模式都有其應當使用的情況,那讓我們看看通路者模式具體應用場景。如果遇到以下場景,此時我們可以考慮使用通路者模式。

如果系統有比較穩定的資料結構,而又有易于變化的算法時,此時可以考慮使用通路者模式。因為通路者模式使得算法操作的添加比較容易。

如果一組類中,存在着相似的操作,為了避免出現大量重複的代碼,可以考慮把重複的操作封裝到通路者中。(當然也可以考慮使用抽象類了)

如果一個對象存在着一些與本身對象不相幹,或關系比較弱的操作時,為了避免操作污染這個對象,則可以考慮把這些操作封裝到通路者對象中。

   通路者模式具有以下優點:

通路者模式使得添加新的操作變得容易。如果一些操作依賴于一個複雜的結構對象的話,那麼一般而言,添加新的操作會變得很複雜。而使用通路者模式,增加新的操作就意味着添加一個新的通路者類。是以,使得添加新的操作變得容易。

通路者模式使得有關的行為操作集中到一個通路者對象中,而不是分散到一個個的元素類中。這點類似與"中介者模式"。

通路者模式可以通路屬于不同的等級結構的成員對象,而疊代隻能通路屬于同一個等級結構的成員對象。

  通路者模式也有如下的缺點:

增加新的元素類變得困難。每增加一個新的元素意味着要在抽象通路者角色中增加一個新的抽象操作,并在每一個具體通路者類中添加相應的具體操作。

  通路者模式是用來封裝一些施加于某種資料結構之上的操作。它使得可以在不改變元素本身的前提下增加作用于這些元素的新操作,通路者模式的目的是把操作從資料結構中分離出來。

繼續閱讀