簡單乾淨的C#方法設計案例:SFCUI.AjaxLoadPage()之二

來源:互聯網
上載者:User

之一,之二

合并顯而易見的代碼

所謂顯而易見的代碼,就是看上去和別處相同的代碼。

在這個例子中,就是View‘中初始頁面顯示的內容與未來重新整理的內容重複;Controller中初始顯示的運算和重新整理的相同。

Controller好辦,如此:

        private void PrepareAssignItemsData(int sprintID)        {            var sprint = ...            var team = ...            var overTimes = ...;            var itemsTreeInSprint = ...            ViewBag.AssignItemsViewModel = ...            ViewBag.ViewModel = ...        }        public ActionResult AssignItems(int sprintID)        {            PrepareAssignItemsData(sprintID);            return View("~/Areas/SFC/Views/Items/ItemTree.cshtml");        }        public ActionResult AjaxRefreshAssignItemsLeftPad(int sprintID)        {            PrepareAssignItemsData(sprintID);            return View("~/Areas/Agile/Views/PlanningMeetings/AjaxRefreshAssignItemsLeftPad.cshtml");        }

 而cshtml頁面中,只需要添加一個在頁面初始化時自動重新整理的函數,就能把<div id = "leftpad">變成空的,由重新整理頁面來填充。代碼變成:

 

<script type = "text/javascript">    $(document).ready(function () {        refreshLeft();    });    function refreshLeft() {        $("#refreshLeft").click();    };</script><div style = "display: no1ne">    @SFCUI.Link("refresh", "/Agile/PlanningMeetings/AjaxRefreshAssignItemsLeftPad?sprintID=" + assignItemsViewModel.Sprint.ID, ajaxUpdateTargetID: "leftpad", ajaxOnSuccess: "refreshAll", id: "refreshLeft")</div><div id = "leftpad"></div>

$(document).ready是多出來的代碼,負責第一次初始化時填充<div id = "leftpad>的內容。

封裝多餘的技術代碼

何為多餘的技術代碼?之前在AjaxValue系列中曾經提到過介面封裝的兩個原則:

最小資訊原則:方法介面應只傳遞最必須的商務資訊。

包括兩個層面:

1. 技術資料不要傳遞

2. 業務資料不能重複

 

現在,先從業務角度分析,這個函數介面設計中,到底哪些資訊是必須的;讓我們來用這一原則,把上面最後的一段cshtml代碼,變成一行代碼。

1. 如果要重新整理,應該調用什麼函數(一般是一個JS函數,提供給左邊的紅框,紅框運行成功,就調用這個JS函數)

2. 用於重新整理頁面的Ajax Url(上述JS函數被調用後,應該到哪個Url擷取重新整理內容)

3. 重新整理成功後,要繼續執行什麼操作(另外一個JS函數,比如重新整理的內容“錯過了document.Ready”要重新套用一下——嘗試了live功能,不知道為什麼無效;或者要串聯重新整理多個地區,本例中沒有)

沒了(後面還會看到一些,不過是為了別的功能)。有幾個東西是多餘的:

1. $(document).ready.....,因為每個AjaxPageLoad都執行,所以是固定的,不用作為參數傳入介面。

2. function refreshLeft() ...{ $"#refreshLeft")....,因為這個按鈕是多餘的,並不需要人手去點擊,只是函數實現中的一個步驟而已。換言之這個按鈕叫什麼都無所謂,只要ready / function / SFCUI.Link(id: ...)中出現的值相同就行,無需人工指定。

3. <div id = "leftpad"></div>也是多餘的!因為既然在這裡寫下那一行代碼,就在代碼處LoadPage,至於Load到什麼東西裡邊,ID叫什麼,都無所謂。

所以,介面調用應該是:

    @SFCUI.AjaxLoadPage("/Agile/PlanningMeetings/AjaxRefreshAssignItemsLeftPad?sprintID=" + assignItemsViewModel.Sprint.ID, refreshFunction: "refreshLeft", ajaxOnSuccess: "refreshAll")

這句話是一個helper,將負責生產前面代碼中提到的<script>及其中的兩個函數ready和refreshLeft、中間的<div>@SFCUI.Link中的Ajax調用</div>、最後的<div id = "leftpad">

下面是Helper的原始碼,裡邊多了一些參數,最後解釋:

        public const string AJAX_LOAD_PAGE_CLASS = "ajaxloadpage";        private static Random _rand = new Random();        public static MvcHtmlString AjaxLoadPage(string pageLink, string refreshFunction = null, string ajaxOnSuccess = null, string style = null, int timeout = 0)        {            int id = _rand.Next();            string html = SFCUI.Link("refresh", "/SFC/Ajax/AjaxLoadPage?pageLink=" + HttpUtility.UrlEncode(pageLink), ajaxUpdateTargetID: id.ToString() + "Body", ajaxOnSuccess: ajaxOnSuccess, cssClass: "hide " + AJAX_LOAD_PAGE_CLASS + " ", id: id.ToString()).ToString();            TagBuilder script = new TagBuilder("script");            script.MergeAttribute("type", "text/javascript");            script.InnerHtml = "$(document).ready(function () { setTimeout(function () {  $(\"#" + id.ToString() + "\").click(); }, " + timeout + "); });";            if (refreshFunction != null)                script.InnerHtml += "function " + refreshFunction + "() { $(\"#" + id.ToString() + "\").click(); };";            html += script.ToString();            TagBuilder pageContainer = new TagBuilder("div");            pageContainer.MergeAttribute("id", id.ToString() + "Body");            pageContainer.MergeAttribute("style", style);            html += pageContainer.ToString();            return new MvcHtmlString(html);        }

1. 先看突然跳出來的int id = _rand.next()

之前提到,我們有很多“隨便”的變數,比如那個"refreshLeft",叫什麼都行,外界不關心。但是如果設為常數,則如果在同一個頁面上放兩個LoadPage的時候,會打架,所以用個Random產生ID。為什麼用static 的呢?因為Random的產生機制,是利用調用時的系統時間作為“種子”,從種子產生下一個隨機數。如果調用時間間隔為“0”,就會產生出相同的種子進而相同的隨機數。static就沒有這個問題了,大家用一個,順著排。

總之,隨機的id代替了"refreshLeft"這個本來需要傳進來的“變數”。

2. TagBuilder script則直接在代碼上方產生一段script,免去了編寫script的工作。

為什麼要判斷refreshFunction為NULL的情況呢?因為有一種情境不會重複重新整理。

在我的項目中,菜單極其複雜,產生菜單的時間,甚至比頁面本身都長。但我們也不像犧牲強大的菜單換取效能,怎麼辦呢?子功能表延時產生!

由於人們在頁面出現後的1~5秒內都不會操作菜單(要離開這個頁面時才會操作),所以我們設定所有繁重的子功能表都使用AjaxLoadPage載入,而且注意最後一個參數timeout,它們多數在1000毫秒後才載入,那時候頁面早就爽快地展示在使用者面前了。

這種情境,不會有人重新整理菜單了,所以就不用RefreshFunction這個參數。

3. TagBuilder pageContainer 代替了原來最後的<div id = "leftpad">,它的id也是隨機產生的,但是由於1、2、3中保持了id的互相照應,雖然外界看不到,但是內部卻順暢運行。

4. 最後多了個style,是我們載入菜單時的需要,這裡就不多說了。

尾聲

合并顯而易見的代碼是初級程式員的基本功,也是產品代碼的基本要求;封裝多餘的技術代碼難度較大,但是只要用心,上述提到的原則也沒有做不到的。

為什麼要費勁封裝呢?散裝的代碼對程式員要求低,只要好好測試,功能相同,也不會出現缺陷,不也一樣嗎?

在16年的IT從業中我發現,所有最後開發面臨崩潰的軟體,很少有受到單個技術難題或缺陷困擾的,多數都百病纏身;而百病纏身的主要問題,是可維護性差;而可維護性差的主要原因,是代碼臃腫重複,尤其是似重複而不重複。

封裝後,則:

1. 總是使用同一段代碼,易於維護。

2. 總是重複使用,代碼的品質有保障。

3. 一個地方發現缺陷,修改代碼後可以同時避免多個地方的缺陷。

4. 在無需深入到技術層面的時候,可以方便地在業務層面閱讀代碼。

5. 把時間花費在深究代碼的封裝上,比重複碼字要有趣得多。

……

在之前的IT職業生涯的“危險職業”系列中有很多人提到:“我一直在做重複勞動,沒有積累,是不是很危險?怎麼辦?”其實萬事萬物看似重複,其實不重複。本人從事Web編程只有一年多(其中只有6個月的編程量超過總工作量的50%),Jquery上上個月剛大致弄明白,但是我相信很多Web編程很久的程式員都不會封裝這些代碼的,而是“重複地”拷貝粘貼代碼。

所以實際上,沒有重複的工作,只有重複的工作心態。

之後我會寫一篇關於“重複勞動中如何提高”的IT職業生涯系列文章。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.