代碼重構——程序員應有的基因


去年幫另一個項目組趕項目時,總是有很多地方令我不舒服。本人編碼有點小小的“潔癖”——即不喜歡見到冗余代碼。即時現在忙,沒時間整理,但是一有時間,我都盡可能的去重構。也許本人是個完美主義者吧。

個人認為重構有以下好處:

  • 改善軟件的性能、質量。
  • 使架構更加合理。
  • 使代碼更容易被理解。
  • 提高軟件的擴展性和可維護性。
  • 提高代碼的重用率,通用性。
  • 提高軟件的開發速度。
  • 更容易發現BUG。
  • 可以提高開發人員的開發水平。

在我見過的很多代碼中,很多程序員寧願無限復制粘貼代碼,也不願意重構代碼。比如經常可以看到這樣一個Switch結構中,每個Case塊除了某個參數不同,里面的代碼幾乎一模一樣。看到這種代碼,不知道是我的悲哀,還是他的悲哀。

這里就展開說說:

一、控件綁定

在開發表單的時候,我們經常會用到下拉列表。如果是服務器控件,我們通常會在后台綁定,但如果是html控件,我們通常需要寫JavaScript來綁定,比如下面這個例子:

$.post(siteBase + "MktUser/Op.aspx?op=items", {}, function(res) {
    if (res != null) {
        // 事業別
        var html = "<option value=''></option>";
        $(res.Data.items).each(function(i, item) {
            html += "<option value='" + item.Id + "'>" + item.Name + "</option>";
        });
        $("#item_id").html(html);
    }
}, 'json');
這是一個綁定下拉列表(select)的例子,如果每次都寫這么多,一個不太復雜的頁面也會讓這些代碼占滿,那么我們可以重構下,如下面的代碼:
function setSelect(se, key, data, val, txt, seval, setf) {
    $.post("Op.aspx?op=" + key, data, function (res) {
        if (res != null) {
            var html = "<option value=''></option>";
            var jsonData = (res.Data.items !== undefined ? res.Data.items : res.Data);
            $(jsonData).each(function (i, item) {
                var jTxt = '';
                var jVal = '';
                $.each(item, function (j) {
                    if (j == val)
                        jVal = item[j];
                    else if (j == txt)
                        jTxt = item[j];
                });
                html += "<option value='" + jVal + "' " + ((seval !== undefined && seval == jVal) ? "selected='selected'" : "") + ">" + jTxt + "</option>";
            });
            $(se).html(html);
            if (setf !== undefined)
                setTimeout(setf, 100);
        }
    }, 'json');
}

 

二、代碼簡化、靈活運用

很多代碼我們可以簡化或者靈活運用。關於簡化,比如使用三元運算符。關於靈活運用,比如很多朋友喜歡將不為空的判斷寫死在JS里,那么我們也可以換一種方式,比如使用html元素的自定義屬性或者文本來判斷,比如:

function valText() {
    var isFlag = true;
    $("td:contains('*')").each(function () {
        var lbl = $(this).text();
        $(this).next().find("input,select").each(function () {
            if ($(this).val() == '') {
                alert("請填寫:o" + lbl);
                isFlag = false;
                return isFlag;
            }
        });
        if (!isFlag)
            return isFlag;
    });
    return isFlag;
}

 

三、代碼歸類

很多人經常羡慕別人有代碼庫,自己總是沒有呢?其實在平常編碼中,只要用心重構就會有了。

在你重構代碼的時候,一般你就會思考,如何重構才能夠更優,如何重構這段代碼就能盡可能多的重復利用(以后也能用),於是乎,有時你會去找找相關的代碼,有時你會把類似的處理邏輯的代碼統一放在一起,比如郵件處理的代碼、文件操作的代碼等等。如果是C#,你可以歸類,如果是JS,你可以考慮放到一個JS文件里。

關於這些,大家可以從這里《也把咱的小類庫拿出來曬曬》打劫。

 

四、提取函數

提取函數很實用,在VS中使用快捷鍵——Ctrl+R+M就能實現提取方法了。提取方法一方面方便代碼重用,另一方面也增加了發現問題的幾率。比如看下面的異常:

 

_shutDownMessage=關鍵目錄的更改通知。
bin dir change or directory rename
HostingEnvironment initiated shutdown
關鍵目錄的更改通知。
bin dir change or directory rename
HostingEnvironment 導致關閉

_shutDownStack=   在 System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
   在 System.Environment.get_StackTrace()
   在 System.Web.Hosting.HostingEnvironment.InitiateShutdownInternal()
   在 System.Web.Hosting.HostingEnvironment.InitiateShutdown()
   在 System.Web.HttpRuntime.ShutdownAppDomain(String stackTrace)
   在 System.Web.HttpRuntime.OnCriticalDirectoryChange(Object sender, FileChangeEvent e)
   在 System.Web.FileChangesMonitor.OnCriticaldirChange(Object sender, FileChangeEvent e)
   在 System.Web.DirectoryMonitor.FireNotifications()
   在 System.Web.Util.WorkItem.CallCallbackWithAssert(WorkItemCallback callback)
   在 System.Web.Util.WorkItem.OnQueueUserWorkItemCompletion(Object state)
   在 System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
   在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   在 System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
   在 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)
從上面文字中,我們可以看到異常捕獲是到方法為止的,比如類似於“未將對象引用到對象的實例”異常,如果沒有報出具體對象的話,茫茫代碼中是很難查找的(在很多情況下無法調試或者無法模擬當時環境時),但是我們可以從最后提示的執行的方法名來限定問題代碼范圍,然后仔細檢查推敲。
 
 

五、方法重載

有時候,可能要滿足多種需求,但是又不想更改代碼,那么方法重載就能派上用場了。比如下面兩個方法:

 

   1:      /// <summary>
   2:      /// 將string類型的fDateTime轉換為formatStr格式的日期類型
   3:      /// </summary>      
   4:      public static string GetStandardDateTime(string fDateTime, string formatStr)
   5:      {
   6:          DateTime s = Convert.ToDateTime(fDateTime);
   7:          return s.ToString(formatStr);
   8:      }
   9:   
  10:      /// <summary>
  11:      ///將string類型的fDateTime轉換為日期類型 yyyy-MM-dd HH:mm:ss
  12:      /// </sumary>
  13:      public static string GetStandardDateTime(string fDateTime)
  14:      {
  15:          return GetStandardDateTime(fDateTime, "yyyy-MM-dd HH:mm:ss");
  16:      }

 

最后

寫了這么多,就此結束吧。

如果你還沉浸在日復一日的重復編碼中,那么就想想重構吧。重構也是個費力活,但是卻可以讓你更上一層樓。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM