[模板] Template 一定要加個 Clone 才對味
今天的一隻蟲是這麼開始的 ...
某使用者反應他每次收到的e-Mail內容是錯的,
根據維護者的介紹知道它的架構大致上是:
主程式是去引用EmailGenerator物件, 然後將ValueObject填入該物件的 Generate() 操作去產生e-Mail內容,
但是主程式每次都會創建EmailGenerator 及 ValueObject 實體, 在封裝下, 不可能有什麼程式可以去改動到ValueObject 內的值, 才是.
再向下一層追去, 出現一個叫TemplateCache的類別, 小弟我的警報器突然響起,
後來查證Log, 果然是在這裡出了問題 ...
原作者是希望付予Template去讀取樣板檔案, 外部程式只需要將值填入PutValue(), 然後呼叫Generator(), 將值填入樣板中, 輸出eMail結果.
但如果每次都去創建一個Template, 就會面臨不斷在IO 讀取檔案的效能問題,
所以加入了TemplateCache , 並實作了Singleton Pattern, 讓Template 可以Reuse.
為了讓送Email可以共用, 又產生了EmailGenerator類別, 讓BuObject可以創建它, 並填入ValueObject就可以完成送eMail的任務了.
原作者到此收工了, 悲劇從此展開 ...
------------------------------------------------------
思考一下, 問題在那裡呢 ?
------------------------------------------------------
這裡有一個很大的問題,
那就是Template是一個全域的物件, 而且還要求被填值, 並產生資料內容.
當Multi Thread時, 一堆執行緒湧入設值, 最後建出來的eMail一定慘不忍賭.
暫時先跳一個tone, 如果在工廠裡, 我們做了一個模板, 可以選擇:
1. 把它填入各式IC, 然後裝機, 等這個機弄完, 再把模板拿出來, 填入另一堆IC, 然後再裝機.
2. 用模板, 做出一堆空板, 再各別填入IC, 再裝機.
原作者就是用了1 , 這是不對的喔 !! 在硬體上沒人這麼玩吧, 但軟體卻很可能發生這種情形.
另外因為他用了EmailGenerator包裝後, 當BuObject在引用時, 雖然每次都用新的創建實體物件, 其實Template還是只有一個喔~
這讓維護者捉了很久的蟲都摸不出頭緒來... 好加在大叔之前也是有害過人的(煙), 才能這時候派上用場,
話說回來, Cache物件一定要受過MultiThread Test Case洗鍊過才能出廠喔! 不然上線有你受的.
解法:
關鍵在於:原作者搞錯要做樣板的是File, 而非Template物件本身.
一、快速解
(1) 為Template類別實作Clone將File的內容Cache住.
(2) 修改TemplateCache.getInstance() 取物件, 回傳Clone物件
二、慢速解
(1) 移除Template原責任操作, 就單純為File的包裝工, 新增一個方法取得樣板的內容.
(2) 由EmailGenerator Facade功能仍在, 將原本Template物件的工作攬下來做, 並修改為私有的操作.
其它解, 就交給大家自由發揮了.
ps. 本篇是無碼, 實在很想睡了...