應用Decorator模式的一個很好的執行個體

來源:互聯網
上載者:User

 本文轉自板橋裡人 

     本文從一個案例分析設計角度,討論了使用設計模式可以比較優雅地實現了品質、功能和效能的統一。很多人以為設計模式是抽象概念,實際上,設計模式是實戰經驗的總結,只有正確使用了設計模式,才明白設計模式真正的運用技巧,避免了過分設計或設計不足。

 案例需求和問題

  多個圖片上傳是很多系統的準系統,一般圖片是一個主體父物件的附屬,如是商店的圖片、是人物的圖片。以下商品Product為例。

  一般一個商品Product有多個圖片Image,他們是1:N關係,表單中圖片的處理不同於文字,使用者需要將圖片專門實現上傳後,後台伺服器系統必須接收和處理這個圖片, 有兩個辦法:
  (1). 首先直接儲存到資料庫,等Product儲存時,再將兩者1:N關係儲存資料庫中;
   這個方案的缺點是:如果使用者上傳圖片後,不再繼續Product操作,那麼,資料庫中就有很多垃圾圖片,這些圖片找不到宿主Product。

  (2). 圖片不儲存到資料庫,先暫存在記憶體中,等Product其它文字屬性欄位儲存時,同時存入資料庫。這個情況將圖片視為文字一樣普通欄位,比較符合實際流程。

  第二個方案可以將圖片儲存到HttpSession中,帶來一個問題:使用者上傳圖片後,有可能需要刪除,圖片有可能是使用者剛剛上傳,儲存在HttpSession中,也可能是在資料庫中(修改商品資料時,同時希望更換商品的圖片,而這時圖片是從資料庫中獲得的)。

  面對這個問題,很多人認為比較簡單,將HttpSession和資料庫都視為資料來源,同時新增或同時刪除,如:

          圖1

  在整個圖片上傳功能中,涉及到幾個功能類:
  首先是圖片列表功能類,用來將HttpSession和資料庫中當前Product下所有圖片顯示出來;
  其次是圖片上傳功能類,顯示一個圖片上傳介面,然後接收上傳的圖片。
  最後是每個圖片的顯示功能類,每個圖片需要專門的功能類處理才能顯示。

  上述三種功能類都涉及圖1的操作,也就是說,這三種功能類中都要和兩種資料來源打交道。

  還涉及到另外可擴充性問題,現在圖片預設的宿主是Product,以後可能是Person或其它任何需要圖片的對象,因此,在這種設計中,我們必須重用圖片上傳功能。

  但是,矛盾在於,資料庫一般是和具體宿主對象Product有具體聯絡的,在圖片上傳功能中必須和資料庫某個具體資料表讀取資料或寫入資料。如何?圖片和宿主的解耦?

  現在,複雜問題出現了,由於加入功能類增多以及重用解耦的要求,使得圖片上傳功能的代碼實現變得複雜。類圖關係如:

 

圖2

  很顯然,這種調用關係非常紛亂,可擴充性很差,如果我們增加新的資料來源,例如,由於圖片檔案都很大,因此我們經常採取緩衝技術,這樣提高圖片顯示速度,這種顯示速度不亞於系統從檔案系統中讀取圖片檔案。如果加入緩衝,那麼所有的功能類都要修改一遍。

  更重要的是,圖2絲毫沒有給出將宿主和圖片解耦的思路,反而是理還亂。很多人的思維停在這裡就沒有前進了,本著夠用就好,KISS或愚笨原則,就會按照圖2思路實現代碼,這樣下去結果是非常可怕的,通常陷入頭痛醫頭、腳疼醫腳的問題,測試人員只有測試到了這個系統的BUG才去修改,但是很多情況下,這種設計錯誤是無法靠測試來糾正的,因為測試不可能窮盡所有實際操作。這也是很多軟體系統不穩定、BUG永遠清除不了的原因之一。

      解決之道

  我無法總結圖1是如何跳躍到圖3的(可能是對此類應用的本質瞭解和模式理解),但是,我們可以知道,圖3給我們思路重新開啟了一道門:

圖3

   我們把HttpSession和資料庫不並列起來,而是串列,這樣HttpSession好像是資料庫的過濾器Filter或代理,這樣如果有Cache機制加入,實際就是在HttpSession和資料庫之間再加一個filter。

   在這種情況下,如果你熟悉GoF的23種設計模式,應該可以發現圖片上傳功能中可以使用設計模式了, Decorator模式是我們推薦的。

圖4

   圖4顯然要比圖2清晰得多,同時似乎一勞永逸解決了伸縮性和擴充性問題,具體Decorator模式實現代碼這裡不羅列,在各個功能類中調用Decorator模式的代碼如下:

ImageFilter imageDbFilter = new ImageProductDbFilter();
ImageFilter imageCacheFilter = new ImageCacheFilter(imageDbFilter);
imageFilter = new ImageSessionFilter(imageCacheFilter);

   從調用代碼看,圖片上傳功能已經可以重用,因為,對於不同的宿主,只要將ImageProductDbFilter()更換為ImageItemDbFilter()就可以了。

   如果將上述代碼寫為:
imageFilter = new ImageSessionFilter(new ImageCacheFilter(ImageProductDbFilter()));

   聯想到Ioc和依賴性注射進而AOP,是不是可以對於不同的宿主應用,將具體ImageProductDbFilter()之類實現子類注射到這個圖片上傳系統中,就可以實現不同應用的圖片上傳功能?

   至此,以後的方向更加清楚了,應該是如何使用AOP或Ioc模式將圖片上傳功能重用提煉到架構中了。

  本文最終想表達的是:設計模式為我們開啟了一扇正確的解決之門,從此我們的系統發生了質變,從程式員自覺樸素的代碼走上了和軟體設計思想發展方向一致的寬廣大道。

  因為你已經將你的系統或模組納入了一個軟體理論體系中,這個理論體系一直在發展,你的系統或模組將會隨著體系發展而有永久的生命力。你的問題不再是孤立的問題,也不再是特殊的問題。

  我的個案如我的孩子一樣,我喜歡將我的個案納入一種體系或標準中去,自此,他就有了發展和可參考發展的餘地了,他就有生命了。

(完)

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.