民初思韻網

加入收藏   設為首頁
選擇語言   簡體中文
你好,請 登陸 或 注冊
首頁 人文思韻 傳奇人物 歷史思潮 時代作品 話題討論 國民思韻 民初捐助 賬戶管理
  搜索  
    人文精神 >>> 技術的天空 溫和的思緒
字體    

C#面向對象設計模式縱橫談 第24講:Visitor 訪問者模式
C#面向對象設計模式縱橫談 第24講:Visitor 訪問者模式
MSDN 網絡廣播 李建忠     阅读简体中文版

2006.10.13 李建忠

類層次結構的變化

類層次結構中可能經常由于引入新的操作,從而將類型變得脆弱……

image

 

動機(Motivation)

在軟件構建過程中,由于需求的改變,某些類層次結構中常常需要增加新的行為(方法),如果直接在基類中做這樣的更改,將會給子類帶來很繁重的變更負担,甚至破壞原有設計。

如何在不更改類層次結構的前提下,在運行時根據需要透明地為類層次結構上的各個類動態添加新的操作,從而避免上述問題?

 

意圖(Intent)

表示一個作用于某對象結構中的各個元素的操作。它可以在不改變各元素的類的前提下定義作用于這些元素的新的操作。

——《設計模式》GoF

 

例說Visitor模式應用

image

假設現在Shape需要增加一個新的MoveTo操作,它所有的子類都需要添加一個MoveTo的Override方法。

image

改進的代碼

image

image

image

image

image

雖然子類的重載方法都是一樣的代碼,但是不能放在基類中寫成virtual方法。因為首先,Visit方法接收的類型不是多態類型,而是具體類型。傳入的this是一種編譯時綁定,它是一種靜態多態。如果是在基類中寫Accept虛方法,里面寫上v.Visit(this),編譯的時候會報錯,因為Visit方法里接收的類型沒有Shape類型,因此我們只能寫在子類中重寫。

現在,給各個子類增加操作,實際上就是給ShapeVisitor增加一個新的子類。

image

當然,操作可能要傳入參數,我們可以為Accept方法添加一個上下文信息

image

客戶程序

image

image

我們首先要new一個ShapeVisitor實例MyVisitor,shape.Accept方法先會執行多態辨析,決定執行Line的Accept方法,然后會執行v.Visit方法,然后找到MyVisitor的Visit方法來執行。整個過程有個雙重辨析,先調用了Accept,此步驟有一個虛函數的動態辨析;然后調用了Visit,此步驟也是一個虛函數的動態辨析。

 

這里有一個問題,我們可以不可以把Visit的參數直接寫成抽象類Shape呢?

image

實際上我們也可以這樣寫,這樣寫了之后,我們只需要在Shape基類中寫上Accept虛方法調用v.Visit(this),即可不需再在子類中重寫Accept方法了。但是這樣寫的問題是,我們在寫ShapeVisitor具體類的Visit方法時,就需要判斷Shape的類型,來做不同的處理。

image

這樣實際上是換湯不換藥,因為本來以前我們的辨析是重載辨析,靠編譯器來解決,現在需要靠我們自己寫if else來解決辨析。這兩種方法都同樣要面臨MyVisitor子類增加的問題。Shape如果增加子類,這種方式也需要增加一個if else分支。

 

結構(Structure)

image

當需要添加新的操作的時候,只需要添加一個ConcreteVisitor類即可。這種結構把擴展操作所帶來的改變轉嫁給了Visitor的子類。

 

Visitor模式的幾個要點

Visitor模式通過所謂雙重分發(double dispatch)來實現在不更改Element類層次結構的前提下,在運行時透明地為類層次結構上的各個類動態添加新的操作。

所謂雙重分發即Visitor模式中間包括了兩個多態分發(注意其中的多態機制):第一個為accept方法的多態辨析;第二個為visit方法的多態辨析。

Visitor模式的最大缺點在于擴展類層次結構(增添新的Element子類),會導致Visitor類的改變。因此Visitor模式適用于“Element類層次結構穩定,而其中的操作卻經常面臨頻繁改動”。

設計模式其實是一種堵漏洞的方式,但是沒有一種設計模式能夠堵完所有的漏洞,即使是組合各種設計模式也是一樣。每個設計模式都有漏洞,都有它們解決不了的情況或者變化。每一種設計模式都假定了某種變化,也假定了某種不變化。Visitor模式假定的就是操作變化,而Element類層次結構穩定。

2010.10.30

2013-08-22 08:54

歡迎訂閱我們的微信公眾賬號!
春秋茶館訂閱號
微信號 season-tea(春秋茶館)
每天分享一篇科技/遊戲/人文類的資訊,點綴生活,啟迪思想,探討古典韻味。
  清末民初歷史人物  民初人物
民族主義思想大師
章太炎(1869年1月12日-1936年6月14日),原名學乘,字枚叔。嗣因反清意識濃厚,慕顧炎武的為人行事而改名為絳,號太炎。中國浙江餘杭人,清末民初思想家,史學家,樸....
為元首清廉不阿至情至性
林森(1868年—1943年8月1日)字子超,號長仁。福建閩侯人。1868年出生于福建省閩侯縣尚干鄉,1884年于臺北電信局工作。1902年到上海海關任職,其間參加反清活....
資助民初精神網
        回頂部     寫評論

 
評論集
暫無評論!
發表評論歡迎你的評論
昵稱:     登陸  註冊
主頁:  
郵箱:  (僅管理員可見)

驗證:   验证码(不區分大小寫)  
© 2011   民初思韻網-清末民初傳奇時代的發現與復興   版權所有   加入收藏    設為首頁    聯繫我們    1616導航