不論是理論上還是實用上,程式碼重用都是程式設計的一個重要議題。可以從兩個角度來討論程式碼重用。
一是邏輯上程式碼以怎樣的方式被重用。既可以通過物件導向的思想普及以來耳熟能詳的繼承的方式。比如先建了一個車的基類,再從它衍生出轎車、卡車、大客車等子類,基類車的功能就被這些子類重用了。另一種途徑是從函式被發明起就一直被使用的組合。例如我們已經有了軲轆、軸、車斗、木杆等部件,就可以組合出一輛三輪車。
第二個角度是實體上程式碼以怎樣的方式被重用。從需要連線的靜態庫檔案、可以動態載入的庫到直接引用的指令碼檔案,都有各自的特點。
Lotus Notes中的程式碼重用也可以從這兩個角度來分析。各種二進位制的設計元素,如表單、檢視,都是採用組合的方式重用程式碼,表單中可重用的部份被做成子表單,建立多個檢視時想要節省工作量,唯一做法就是將列作為元件重用。至於LotusScript和Java程式碼,則像其他程式語言一樣,繼承和組合兩種方式都可選用。
LotusScript作為Xpages被引入之前Notes最主要的程式語言,是一種解釋型的指令碼語言,但又和VB一樣,原始程式碼會被先編譯成一種中間形式的程式碼,使用LotusScript的其它Lotus軟體,如Lotus 1-2-3、Lotus Word Pro等,有些可以把編譯過的LotusScript以副檔名為.LSO的檔案形式儲存和引用。Lotus Notes不支援這種方式,而是將編譯過的程式碼和原始程式碼一同儲存在包含此LotusScript的設計元素裡。在代理、指令碼庫、表單等含有LotusScript的設計元素裡,分別可以看到資料型別為Agent LotusScript的以下欄位$AssistAction_Ex、$ScriptLib_O、$$FormScript_O、$$Script_O,其中的內容都是被稱為Script Object的編譯過的LotusScript。這樣在解釋執行前的編譯,雖然使LotusScript執行得更快,但也給位於不同設計元素的指令碼之間的呼叫帶來了一個副作用。可複用的指令碼通常集中置於指令碼庫中,表單、代理等再引用這些指令碼庫。儲存於這些呼叫方設計元素內的編譯過的指令碼包含了指令碼庫裡各個可供呼叫的公用專案如變數、函式、類的資訊。
當指令碼庫中的程式碼發生變化被重新編譯後,呼叫它的設計元素儲存的那些公用專案的資訊就可能與指令碼庫的實際不一致,這就導致了常見的執行時錯誤Type mismatch on external name <name>和Cannot find external name <name>。如果被使用的變數、函式真的發生了變化,如被刪除、修改名稱、引數和返回型別等等,指令碼當然無法執行,與是否編譯無關。但實際上,即使這些都沒有發生變化,這些錯誤也時常會產生。要避免它們,就需在修改了指令碼庫後,把使用到它的設計元素裡的指令碼編譯一遍,也就是把它們稍作修改再儲存,或者是使用Designer的重新編譯所有LotusScript命令。一般來說,指令碼庫的各個公用專案宣告發生變化,呼叫方一定需要重新編譯;如果是私有專案如私有變數或一個類的私有成員被修改,或者函式的內部程式碼發生變化,呼叫方不需要重新編譯。
在重用的實體方面,某個應用要重用其他應用的程式碼都必須置於同一個資料庫中,即每重用一次,都建立了這些程式碼的一份副本,而不是引用同一份程式碼。50. 替換設計和重新整理設計——Lotus Notes的程式部署和更新之理論和51. 替換設計和重新整理設計——Lotus Notes的程式部署和更新之實踐討論的Lotus Notes程式繼承設計的很多問題,都和這個事實有關。再加上上面介紹的關於編譯的問題,就使得通常模版發生變化後,要更新使用它的應用程式,不僅要替換或重新整理設計,還可能需要再設計更新後,重新編譯所有指令碼。
這種重用實際上是囿於Lotus Notes架構的不理想的模式。為此,Lotus Notes理論上也提出瞭解決方案——單一副本模版。資料庫的設計繼承自這種模版時,只會為每個設計元素生成一個連結到原始設計元素的引用,用到某個設計元素時,Lotus Notes會依據這個引用自動獲得模版裡的設計元素。如果為這個資料庫建一個副本或拷貝,Notes則會將引用替換成實際的設計元素,以免這個新的資料庫所在的環境沒有單一副本模版。
聽起來似乎很理想,實際應用時由於Lotus Notes的特性和場景的制約還需要額外的注意。我們知道Notes客戶端有良好高效的快取機制。開啟某個伺服器上的應用時,Notes客戶端會把初次讀取到的設計元素,如表單、檢視、代理等,快取到desktop8.ndk檔案(不同版本的快取檔案的名稱稍有不同),也可以用“工作臺屬性”檢視和壓縮這個檔案。下次再用到這個設計元素時,Notes就會直接使用快取中的版本,省去讀取伺服器上的資料庫。直到關閉這個資料庫時,此次會話結束,快取失效。下次再開啟同一個資料庫時重新從遠端資料庫下載和快取設計元素。這個機制和單一副本模版珠聯璧合。如果伺服器上的多個資料庫繼承自位於同一伺服器的一個單一副本模版,我們修改了這個模版裡的某個表單或代理,所有引用了它們的資料庫在使用者下次開啟時都會自動使用最新的版本。
但這樣的場景和實際環境仍然有差距。我們在以前提到過,正式伺服器通常不會允許開發人員直接修改其上的資料庫的設計,這樣剛才所述的自動更新就失去了前提。如果是在本地開發環境下,原本這樣做是可行而且有效的。但是Notes客戶端對本地資料庫的設計元素的快取似乎另有途徑,在模版被修改後,即使退出再重新進入繼承它的資料庫,看到的仍然是舊的設計元素,除非關閉Notes客戶端重新開啟,更新才見生效。另一種方法則是模版修改後,手工再次重新整理繼承它的資料庫的設計。
並且,單一副本模版裡的LotusScript修改後,繼承此模版的資料庫仍然很可能需要重新編譯指令碼才能避免前面討論的錯誤,而在“重新編譯所有LotusScript”的過程中,為了儲存編譯後的程式碼,Notes會將原來引用設計元素的連結先替換成元素實體,這樣情況又變得和繼承普通模版一樣,單一副本模版裡的修改再也不能直接反映到繼承它的資料庫。要恢復單一副本模板的本意,只有對繼承設計的資料庫再次重新整理設計。
所以能夠有效應用單一副本模版的場景就像Lotus Notes幫助中作為例子提出的大量設計穩定不變的郵箱繼承一個單一副本的郵箱模版,以節省大量重複的設計元素佔用的空間。