其實也不能說是小技巧,只是大家可能會沒有重視。這是需要先說明的,否則會被我的標題迷惑,因為我要描述的內容,真是尋常無比。
編寫Remoting程式,通常分為三部分:遠程對象、服務端程式、用戶端程式。如果不考慮中繼資料的安全性,我們會把遠程對象的dll產生相同的兩份,分別放到服務端和用戶端。Remoting在用戶端的調用是很簡單的,但調試起來就沒有那麼容易。因為用戶端和伺服器端分別屬於不同的應用程式定義域,無法設定斷點進行單步調試。如果瞭解NUnit,大家會知道NUnit也是不支援分布式應用程式的調試的,至少是支援得不夠好。
所以,在實際做項目的過程中,我更傾向於先調用本地的對象,等調試成功後,再開啟Remoting服務,調用遠程對象,驗證是否正確。舉例來說,我要提供訪問資料庫的遠程對象。我會先讓該對象在本地運行,並調用其方法。如果一切正常,說明資料庫的配置和串連均是正確的。然後再將該調用替換為遠程對象。如果程式出錯,則可以肯定是Remoting提供的服務出錯了,或者是遠程對象未按照Remoting的規定,沒有派生MarshalByRefObject,或者未提供序列化特性。
最初我使用了最愚蠢的辦法,就是寫兩行調用,一個調用本機物件,一個調用遠程對象。然後根據實際的情況,酌情考慮注釋某一行代碼。如此這般用了一段時間,終於覺得麻煩,迫使我改變方法了。其實很簡單,就是為用戶端程式的主類中,多寫一個建構函式而已,呵呵:)
例如,遠程對象是一個訪問資料庫的Remoting服務,派生MarshalByRefObject的主類名為DBAccessService。那麼我首先定義一個枚舉,分別標明是屬於本地調用還是遠程調用:
public enum InvokeMode
{Local=0,Remoting}
對於用戶端程式,如果主類為DataBaseOperate,那麼就需要增加一個建構函式和遠程對象欄位:
public DataBaseOperate(InvokeMode invokeMode)
{
switch (invokeMode)
{
case InvokeMode.Local:
serviceObj = new DBAccessService();
break;
case InvokeMode.Remoting:
serviceObj = (DBAccessService)Activator.GetObject(typeof(DBAccessService),"tcp://localhost:8080/DBAccessService");
break;
}
}
private DBAccessService serviceObj = null;
如此這般,在用戶端調用對象時,就可根據設定建構函式中的參數枚舉值,靈活地改變用戶端調用對象的方式。
其實這種辦法也可以用簡單原廠模式來完成。不過這個簡單工廠生產的產品和通常意義的原廠模式有點不一樣哦,因為他們的產品其實是完全相同的。不同的僅僅是建立對象的方式而已。
public class SimpleFactory
{
public static DBAccessService CreateInstance(InvokeMode invokeMode)
{
switch (invokeMode)
{
case InvokeMode.Local:
return new DBAccessService();
break;
case InvokeMode.Remoting:
return (DBAccessService)Activator.GetObject(typeof(DBAccessService),"tcp://localhost:8080/DBAccessService");
break; }
}
}
然後再調用工廠的靜態方法,來獲得該對象即可。
兩種方法都是一種思想:就是根據需要,選擇不同的建立方式(其實前一種方法也可以看作是簡單原廠模式的一種變種)。如果只有一個要建立的對象,選前者更為方便;如果需要建立多個對象,用Factory 方法提供多個靜態方法,應該要靈活一些。
通過上述方法,不僅便於調試,也便於以後代碼的修改。如果取消使用Remoting,只需改變參數枚舉值即可,其他代碼通通不用改變。這個技巧也算是設計模式的一種最簡單應用吧。