1. 程式人生 > >淺談三層架構中的實體類(C#)

淺談三層架構中的實體類(C#)

         最近因為三層架構中的實體類,引發了不少小問題,下面列舉一下,談談自己的感想。

         本文所指的實體類僅限於三層中的實體類,即資料庫表的對映。

一、為什麼要用實體類?

         |  使程式簡潔易懂,便於維護。

         |  暗合介面不變原則。

         |  體現面向物件思想。

        舉例說明:

         不用實體類的三層

        假如程式有所變動,需要增加一個引數,學生年齡

        用實體類的三層

        同樣增加一個引數,學生年齡

         很明顯的看出,用實體類之後,程式碼明顯變得簡潔,面向物件封裝思想。

         最重要的是,如果將來有所改動,只需要改動實體類,方法間呼叫介面,完全不需要變動,大大減少了程式修改量,迎合了面向物件中介面不變的思想。

         甚至在程式設計時,就把將來可能需要的屬性預先放在實體類中,這樣以後變動時,連實體類都不用變動。

二、實體類缺點在哪(僅是個人觀點)?

         雖然實體類有明顯的優勢,但親身使用時會發現一個明顯的問題:程式碼可讀性貌似降低了。

         上邊例子中體現的不是很明顯。再來一個簡單的例子。

         假如有一個方法(沒有用實體類):

         selectByPartDate(DateTime startDate,DateTime endDate){}

         此方法用來查詢某段時間內的記錄,兩個引數:一個是起始時間,一個是結束時間。

         雖然沒有用實體類,可是讓人看起來很舒服,一看就知道要幹什麼。

         用了實體類後(假設實體類名是LoginLog):

         selectByPartDate(LoginLog startDate, LoginLog endDate){}

         讓人看了不知所措,難以理解到底想做什麼。

         當然,這種不知所措可以通過兩個途徑解決:

         |  良好的命名規範,達到 “見名知意”。

         |  良好的文件說明或者程式碼註釋。

         在這,引出一個問題:三層中,所有的方法都要用實體類傳遞引數嗎?

         最明顯的就是上邊selectByPartDate例子,還有諸如:deleteByID(longid){}這樣的方法。真的有必要傳遞實體類嗎?

         實體類的確是容易擴充套件、修改,可這不違反設計原則嗎?

         設計原則是:儘量避免對原有程式碼的修改,而是通過增加程式碼的方式去解決。

         諸如selectByPartDate、deleteByID這樣的方法,目的已經很明確了:查詢某段時間內的記錄、根據id刪除記錄。換句話說,這就是它們存在的意義。

         程式再怎麼擴充套件,能涉及到這類方法?假如真的把這類方法擴充套件了,那麼它們完全失去了自己的意義!

         deleteByID就是根據id刪除,擴充套件了,就不是根據id刪除了!這時候你可以再新增一個新的方法,何必和deleteByID過不去呢?

         對於引數極少,目的明確的方法,個人認為沒必要用實體類。

         這只是我的個人看法,歡迎高人指點!

三、源自實體類的靈感!

         三層中,大家都知道U層的邏輯應該儘量少,儘可能的轉移到B層。

         但是實際應用中如何轉移卻是個問題。

         就拿刪除記錄來說,U層呼叫B層,B層呼叫D層,由D層返回布林值,來說明刪除是否成功。

         這樣傳遞引數,最終U層得到的是一個布林值,真或假,攜帶的資訊太少了,只能反饋給使用者成功或者失敗(同時多了一次判斷邏輯),而為什麼失敗,就無從得知了。

         現實應用中有很多這樣的例子,有時候為了給出使用者更詳細的提示,不惜把B層分的很細,然後在介面大量的呼叫B層方法,加上大量的判斷,才能給使用者一個完整的提示。

         這樣的情形顯然不是我們想要的?那麼怎麼解決呢?

         造成這種情況的根本原因就是布林型返回值攜帶的資訊太少,哪個型別多?當然是字串型!

         在D層,可以返回布林值,讓B層判斷使用。但是B層返回給U層的值,強烈反對是布林型的!

         按照這個思路,在B層使用複雜的邏輯,然後把執行結果以字串的形式的返回。這樣一來,U層無需任何判斷,直接把B層返回的字串顯示出來就行了!

         舉個例子(B層的一個方法):

  1. public string deleteMail(string domainName, Mail mail)
    
    {
    
    try
    
    {
    
    //刪除POP3伺服器中的郵箱
    
    CMDHelper cmdHelper = new CMDHelper();
    
    string cmdString = "";
    
    cmdString = cmdHelper.execute("DEL " + mail.mailName + "@" + domainName + " /DELETEUSER");
    
    if (cmdString.ToLower().IndexOf("successfully") >= 0) //刪除成功
    
    {
    
    //同步資料庫
    
    IMailDAO mailDAO = creater.createMailDAO();
    
    if (mailDAO.deleteByID(mail))
    
    {
    
    return "刪除成功!資料庫同步成功!";
    
    }
    
    else
    
    {
    
    return "刪除成功!但資料庫同步失敗!";
    
    }
    
    }
    
    else if (cmdString.IndexOf("系統找不到指定的檔案") >= 0) //不存在
    
    {
    
    return "該郵箱不存在!";
    
    }
    
    else
    
    {
    
    return "未知原因錯誤!請聯絡管理員!";
    
    }
    
    }
    
    catch (Exception ex)
    
    {
    
    throw ex;
    
    }
    
    }

         很明顯的看出,一切判斷都是在B層完成的,然後把結果以字串形式返回給U層,簡潔明瞭,U層不需要任何邏輯,直接show就行了!

         這樣看上去很好,但是字串還是比較讓人不舒服,既然是面向物件,為何不返回一個實體類呢?

         我們可以定義一個實體類,名字就叫LayerParameter。給這個實體類加一個字串型的resultString屬性,就把剛剛的字串返回值封裝進來了。就用這個實體類作為B層給U層的返回值。

         這樣做簡直完美!

         有經驗的朋友可能遇到過重新整理介面的問題,也就是U層需要根據實際情況來重新整理介面資料,在B/S結構中尤其明顯。有了實體類做返回值,就啥都不怕了!不就是重新整理嗎?在LayerParameter實體類中加一個布林型屬性refresh,U層呼叫B層後,show一下返回值(LayerParameter類例項)的resultString屬性,把執行資訊告訴使用者,然後再判斷一下refresh屬性,決定是否重新整理介面資料(U層一點邏輯都沒有是不可能的!),此時B層給U層的返回值,仍然是LayerParameter,介面無需任何改動。

         以上僅僅是個人想法,希望大牛指點!

         最後,申明一點:

         一切的一切還是要以專案實踐為基礎,經驗才是王道,否則一切討論都是空穴來風!

--------------------- 本文來自 yangyuankp 的CSDN 博,全文地址請點選:https://blog.csdn.net/yangyuankp/article/details/7880943?utm_source=copy