「硬核」代碼重構

在學習編程的路上,相信你們這幾個詞必定很多聽,什麼 面相對象、封裝繼承多態、內功心法21種設計模式 等等 。可是卻不多用到,或者說用到的都是被動使用。大牛們在寫代碼前早就構思好了,接口,基類等等。本身寫代碼的時候,不多有把面向對象想的面很全,很容易在趕上不夠優秀的代碼,這時候就須要重構了。前端

可是咱們卻不多去重構,可能緣由有不少,好比很重要的一點:不想改出Bug;不想增長工做量(我是要5點半下班的男人,女友還在等我作飯);時間很緊,先實現功能先;代碼是82年的不敢動!!!git

其實重構能夠寫出更健壯的代碼、減小後面的工做量、讓開發者更好閱讀。看了不少重構的文章,發現不少是一些基本的,命名規範或者拆函數什麼的。這篇文章寫下我重構的一些思路和重構以前代碼對比。好了,廢話很少說,上項目。威武、威武、威武........github

簡單介紹一下項目,項目就是一個客戶端小工具用來審覈編寫遞交的說明是否規範。這裏說下,面向對象是一種思想,和語言無關。只要是面嚮對象語言,不管你是C#、Java、TypeScript、Python,都是能夠用這種思想重構的。正則表達式

tools.png

上圖就是小工具了一個部分截圖,有若干個欄,每一個欄都是填寫一些對應的修改內容,在審覈校驗時,會檢查寫的內容是否符合標準。編程

前輩已經完成一些欄的校驗,個人任務是完成剩下欄:寫正則表達式,而後在不標準的時候提示就行了,是否是以爲根本沒有必要重構,依葫蘆畫瓢就行了在我拿到代碼的時候,是這樣的代碼:設計模式

// 下面變量是和界面綁定的變量,RaisePropertyChanged做用在變量改變的時候通知前端從新渲染
// 不熟悉C#代碼的,只用知道這些變量就是和前臺綁定的就是了

    private string _editDescription;
    /// <summary>
    /// 修改說明內容
    /// </summary>
    public string EditDescription
    {
        get { return _editDescription; }
        set
        {
            _editDescription = value;
            RaisePropertyChanged(() => EditDescription);
        }
    }

    private string _editDescriptionRules;
    /// <summary>
    /// 修改說明校驗規則
    /// </summary>
    public string EditDescriptionRules
    {
        get { return _editDescriptionRules; }
        set
        {
            _editDescriptionRules = value;
            RaisePropertyChanged(() => EditDescriptionRules);
        }
    }

    private bool _editDescriptionHasValidationError;
    /// <summary>
    /// 修改說明校驗標誌
    /// </summary>
    public bool EditDescriptionHasValidationError
    {
        get { return _editDescriptionHasValidationError; }
        set
        {               
            _editDescriptionHasValidationError = value;
            RaisePropertyChanged(() => EditDescriptionHasValidationError);
        }
    }

    private string _integratedNote;
    /// <summary>
    /// 集成注意內容
    /// </summary>
    public string IntegratedNote
    {
        get { return _integratedNote; }
        set
        {
            _integratedNote = value;
            RaisePropertyChanged(() => IntegratedNote);
        }
    }

    private string _integratedNoteRules;
    /// <summary>
    /// 集成注意規則
    /// </summary>
    public string IntegratedNoteRules
    {
        get { return _integratedNoteRules; }
        set
        {
            _integratedNoteRules = value;
            RaisePropertyChanged(() => IntegratedNoteRules);
        }
    }

    private bool _integratedNoteHasValidationError;
    /// <summary>
    /// 集成注意校驗標誌
    /// </summary>
    public bool IntegratedNoteHasValidationError
    {
        get { return _integratedNoteHasValidationError; }
        set
        {
            _integratedNoteHasValidationError = value;
            RaisePropertyChanged(() => IntegratedNoteHasValidationError);
        }
    }
     
// 這裏隨便舉了兩欄的變量,後面還有若干欄。
複製代碼

依葫蘆畫瓢之後呢,我發現原來是這樣的。每一欄用了單獨三個變量直接去綁定:編寫的內容、是否標準的標誌、不標準提示語。我是一個懶人啊,在我畫了兩個瓢之後,就很煩(一直在那複製變量,在那改來改去),這些個變量都是差很少一個意思。爲啥讓我重複在複製,修改呢?bash

明顯每欄有相同項啊,對不對,一個是內容,一個狀態,一個是錯誤提示語啊,咆哮!!!函數

這時候,我想起了書本上的一句話: "早重構,常重構"工具

我已經安奈不住我那顆懶惰的內心,由於下面還有「狠多狠多」欄,每一行有三個相似的變量,我這依葫蘆畫瓢,這個星期加班,就在複製粘貼去了。我是要上進,要天天進步的人,不能這樣!學習

我爲啥不能將這相同的共性抽象出來呢?是不咯,這個時候,我想起了《葵花寶典》的第一頁的第一句:「萬物皆對象」,因而本能的告訴我,每一欄看作一個對象,只是每欄的值不同。而後我就寫了一個」雞肋「(基類),代碼以下:

/// <summary>
    /// 欄 基類
    /// </summary>
    public class Base: ObservableObject
    {
        private string _content;
        /// <summary>
        /// 內容
        /// </summary>
        public virtual string Content
        {
            get { return _content; }
            set
            {
                _content = value;
                RaisePropertyChanged(() => Content);
            }
        }

        private string _errorTip;
        /// <summary>
        /// 錯誤提示
        /// </summary>
        public virtual string ErrorTip
        {
            get { return _errorTip; }
            set
            {
                _errorTip = value;
                RaisePropertyChanged(() => ErrorTip);
            }
        }

        private bool _isError;
        /// <summary>
        /// 是否錯誤
        /// </summary>
        public virtual bool IsError
        {
            get { return _isError; }
            set
            {
                _isError = value;
                RaisePropertyChanged(() => ErrorTip);
            }
        }
    }
複製代碼

virtual是爲了讓子類可以重寫get和set(若是有需求的話,爲後面擴展作準備),而後字段從3個變到了1個了。

/// <summary>
/// 修改說明欄
/// </summary>
public class EditDescription : Base { }		
private EditDescription _editDescriptions;
/// <summary>
/// 修改說欄綁定變量
/// </summary>
public EditDescription EditDescriptions
{
    get { return _editDescriptions; }
    set
        {
            _editDescriptions = value;
            RaisePropertyChanged(() => EditDescriptions);
        }
}
        
// 其餘的同樣,我就很少寫了
複製代碼

那,咱們來算一下帳,原先的變量,每一欄有3個變量,一個變量有6行代碼的話,假如我這個有100欄,就是:

重構前: 100(欄)x3x6 = 1800 行代碼 (阿西吧!!!)。

重構後: 100(欄)x1x6 = 600 行代碼 。

小學算數: 1800 - 600 = 1200 (1200行,你說乾點啥很差啊)

秀兒們算下,你花這麼多時間,在那複製粘貼,不敢去動前輩們的代碼,仍是勇敢一點呢?

而後是否是感受到一個繼承就簡單了不少呢,這只是一個面向對象的簡單運用,就讓咱們少寫了這麼多代碼。

前輩和我說,寫代碼就像練武功,就像你會了「九陽神功」或者"吸星大法",學其餘武功看一眼就會。也就是說,當你理解了面向對象之後呢,你天然而然的就會寫出很精簡的代碼了。阿西吧,又扯遠了。

變量好了,擡頭一看函數,個人臉便有點抽搐,啊!!這函數有毒!函數是這樣的:

// 此處函數用來設置每一欄報錯時邊框變紅
    private void SetValidateFlag()
    {
        // 綁定的實體類判斷狀態
        if (tsEntity.EditDescriptionHasValidationError)
        {
            // 控件邊框改顏色
            EditDescriptionHsExpander.BorderThickness = new Thickness(1);
            EditDescriptionHsExpander.BorderBrush = _readBrush;
        }

        if (tsEntity.TestSuggestionHasValidationError)
        {
            TestSuggestionHsExpander.BorderThickness = new Thickness(1);
            TestSuggestionHsExpander.BorderBrush = _readBrush;
        }

        if (tsEntity.IntegratedNoteHasValidationError)
        {
            IntegratedNoteHsExpander.BorderThickness = new Thickness(1);
            IntegratedNoteHsExpander.BorderBrush = _readBrush;
        }
        // 此處省略一萬個if,每一個欄都有一個if
    }
複製代碼

而後你們懂的嘛,在我改了兩欄之後,我又耐不住性子了。再一看,感受似曾相識燕歸來的感受啊!有沒有,每一個if中都有三個相似的東西。我那個心啊,又忍不住悸動了起來,像是等初戀的感受,想她來,來了又不知道要幹哈。而後我發現其實if中判斷的就是每欄的狀態,括號裏面是對控件欄的設置。而後想嘛,能不能搞個相似循環的東西,只要寫一個for就行了呢。

思考之後,是這樣的,我把控件也變成了欄的一個屬性了,這樣if判斷裏面就都是判斷一個類了。代碼就變成了這樣:

public class Base: ObservableObject
    {
        /// <summary>
        /// 模塊控件(新增)
        /// </summary>
        public object Control { get; set; }
        
        //其餘的和上面的Base同樣
    }
複製代碼

而後 SetValidateFlag() 函數就變成了這樣:

/// <summary>
    /// 設置校驗界面效果
    /// </summary>
    private void SetValidateFlag()
    {
        // listBase 全部欄實體集合
        foreach (var item in listBase)
        {
            if (item.IsError)
            {
                var control = item.Control as HsExpander;
                if (control == null)
                    continue;
                // 將控件的邊框變成紅色
                control.BorderThickness = new Thickness(1);
                control.BorderBrush = _readBrush;
            }
        }
    }
複製代碼

好了嘞,好好的一個if的葫蘆瓢給咱給整沒了。這時候咱們來算算咱們這個重構,省了多少事。老樣子:

原先的一個if算5行代碼,我這個有100欄,就是:

重構前: 100(欄)x 5 = 500 行代碼 (全是if啊)。

重構後: 我數了一下,沒有錯的話應該是:14行代碼 。

重構一下之後,變量獲得了減小且對外統一。感受一顆心獲得了小小知足,感受靈魂獲得了昇華,不知道是本身太容易知足,仍是代碼世界裏給個人成就感。感受「乾坤大挪移」瞬間上了兩層。

這就是我在寫代碼的時候一個小小的重構思路,但願可以幫助到你們一點。而後這個是個人Github,若是有幫助到你們的項目,能夠給我點個star, 小生在這邊謝謝啦!!!

相關文章
相關標籤/搜索