剪貼簿中的觀察者(Observer)模式

softart發表於2007-10-27
2007年08月30日 23:18:00

最近因為工作需要,使用到了剪貼簿的特殊功能。也翻閱了一些網上介紹的資料,發現要實現類似FlashGet那樣下載工具中監視剪貼簿的實現方式,對我們程式設計有點借鑑的意義。

在Windows提供的剪貼簿API中,針對監視這塊,提供的是序號產生器制。主要函式是SetClipboardViewer這個API函式。這個函式的宣告是這樣的(Delphi):

function SetClipboardViewer(hWndNewViewer: HWND): HWND; stdcall;

通過這個函式,將一個視窗控制程式碼,註冊到系統剪貼簿中。可以稱註冊後的窗體為一個Clipboard Viewer,眾多的Viewer形成一個Clipboard Viewer Chain。這個Chain是一個典型的連結串列,前一個記住下一個的指標。

註冊為Viewer的Handle所在的窗體,通過處理WM_CHANGECBCHAIN和WM_DRAWCLIPBOARD兩個訊息,來處理所有來自剪貼簿的變化。處理這些訊息的時候,記住向下一個Viewer傳遞訊息,程式碼類似於

SendMessage(hwndNextViewer, message, wParam, lParam);

我重點並不是要說明程式碼如何編寫,只是簡單地介紹了這個"監控"的實現方式。我們很容易聯想到,這和設計模式中提到的Observer模式是非常類似的。最大的不同點在於,剪貼簿直接使用了訊息系統作為解耦的方式。

正因為有這個相似的地方,我才願意仔細分析一下這種實現方式的優點和缺點。

先來說說優點:

  1. 目標和觀察者之間完全解耦,不需要定義特定介面。
  2. 觀察者可以在任意Window上附加實現。這在很多窗體應用的程式來說非常方便。
  3. 可以很方便地實現跨程式、執行緒的觀察者。這得益於標準的訊息機制。
  4. 跨語言實現沒有什麼問題。
  5. 使用PostMessage和SendMessage可以實現兩種完全不同的更新方式。Subject可以選擇等待和不等待Observer更新完成。

看了這些有點,最重要也是最核心的,就是解耦。再來分析一下缺點:

  1. 程式設計的過程,必須做到約定程式設計。約定程式設計和契約程式設計最大的差異在於沒有編譯機制。
  2. 在觀察者中可以方便地改變後續觀察者的行為,也可能完全破壞其他的正常功能。據說NetAnts曾經在這方面就有過BUG,導致其他程式無法貼上資料。
  3. 一般我們的應用場景中,除了M-V(模型-檢視)的模式,還有M-M(模型-模型)的方式,針對第二種方式,這種實現方式不是很適合。
  4. 沒有訊息系統的程式中,不適合使用。比如控制檯程式。
  5. 對響應時間要求很高的系統,不適合。因為訊息的響應時間不可控制。

分析完上面的這些有點和缺點,我其實更傾向於從這類設計中吸取Message這個設計元素。巧妙地使用Message,可以有意想不到的效果。

總結一下,設計模式的基本原則之一就是解耦,而Message的特性之一就是解耦。這也就是為什麼我們會發現剪貼簿的監視方式和我們學習的Observer模式很想像的根本。所以說他是模式一點也不為過。只不過少了點OO的味道。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1766118


相關文章