“硬核”代码重构
在學(xué)習(xí)編程的路上,相信大家這幾個(gè)詞一定不少聽(tīng),什么 面相對(duì)象、封裝繼承多態(tài)、內(nèi)功心法21種設(shè)計(jì)模式 等等 。但是卻很少用到,或者說(shuō)用到的都是被動(dòng)使用。大牛們?cè)趯?xiě)代碼前早就構(gòu)思好了,接口,基類(lèi)等等。自己寫(xiě)代碼的時(shí)候,很少有把面向?qū)ο笙氲拿婧苋?#xff0c;很容易在遇上不夠優(yōu)秀的代碼,這時(shí)候就需要重構(gòu)了。
但是我們卻很少去重構(gòu),可能原因有很多,比如很重要的一點(diǎn):不想改出Bug;不想增加工作量(我是要5點(diǎn)半下班的男人,女朋友還在等我做飯);時(shí)間很緊,先實(shí)現(xiàn)功能先;代碼是82年的不敢動(dòng)!!!
其實(shí)重構(gòu)可以寫(xiě)出更健壯的代碼、減少后面的工作量、讓開(kāi)發(fā)者更好閱讀。看了很多重構(gòu)的文章,發(fā)現(xiàn)很多是一些基本的,命名規(guī)范或者拆函數(shù)什么的。這篇文章寫(xiě)下我重構(gòu)的一些思路和重構(gòu)之前代碼對(duì)比。好了,廢話(huà)不多說(shuō),上項(xiàng)目。威武、威武、威武........
簡(jiǎn)單介紹一下項(xiàng)目,項(xiàng)目就是一個(gè)客戶(hù)端小工具用來(lái)審核編寫(xiě)遞交的說(shuō)明是否規(guī)范。這里說(shuō)下,面向?qū)ο笫且环N思想,和語(yǔ)言無(wú)關(guān)。只要是面向?qū)ο笳Z(yǔ)言,無(wú)論你是C#、Java、TypeScript、Python,都是可以用這種思想重構(gòu)的。
上圖就是小工具了一個(gè)部分截圖,有若干個(gè)欄,每個(gè)欄都是填寫(xiě)一些對(duì)應(yīng)的修改內(nèi)容,在審核校驗(yàn)時(shí),會(huì)檢查寫(xiě)的內(nèi)容是否符合標(biāo)準(zhǔn)。
前輩已經(jīng)完成一些欄的校驗(yàn),我的任務(wù)是完成剩下欄:寫(xiě)正則表達(dá)式,然后在不標(biāo)準(zhǔn)的時(shí)候提示就好了,是不是覺(jué)得根本沒(méi)有必要重構(gòu),依葫蘆畫(huà)瓢就好了在我拿到代碼的時(shí)候,是這樣的代碼:
// 下面變量是和界面綁定的變量,RaisePropertyChanged作用在變量改變的時(shí)候通知前端重新渲染 // 不熟悉C#代碼的,只用知道這些變量就是和前臺(tái)綁定的就是了private string _editDescription;/// <summary>/// 修改說(shuō)明內(nèi)容/// </summary>public string EditDescription{get { return _editDescription; }set{_editDescription = value;RaisePropertyChanged(() => EditDescription);}}private string _editDescriptionRules;/// <summary>/// 修改說(shuō)明校驗(yàn)規(guī)則/// </summary>public string EditDescriptionRules{get { return _editDescriptionRules; }set{_editDescriptionRules = value;RaisePropertyChanged(() => EditDescriptionRules);}}private bool _editDescriptionHasValidationError;/// <summary>/// 修改說(shuō)明校驗(yàn)標(biāo)志/// </summary>public bool EditDescriptionHasValidationError{get { return _editDescriptionHasValidationError; }set{ _editDescriptionHasValidationError = value;RaisePropertyChanged(() => EditDescriptionHasValidationError);}}private string _integratedNote;/// <summary>/// 集成注意內(nèi)容/// </summary>public string IntegratedNote{get { return _integratedNote; }set{_integratedNote = value;RaisePropertyChanged(() => IntegratedNote);}}private string _integratedNoteRules;/// <summary>/// 集成注意規(guī)則/// </summary>public string IntegratedNoteRules{get { return _integratedNoteRules; }set{_integratedNoteRules = value;RaisePropertyChanged(() => IntegratedNoteRules);}}private bool _integratedNoteHasValidationError;/// <summary>/// 集成注意校驗(yàn)標(biāo)志/// </summary>public bool IntegratedNoteHasValidationError{get { return _integratedNoteHasValidationError; }set{_integratedNoteHasValidationError = value;RaisePropertyChanged(() => IntegratedNoteHasValidationError);}}// 這里隨便舉了兩欄的變量,后面還有若干欄。 復(fù)制代碼依葫蘆畫(huà)瓢以后呢,我發(fā)現(xiàn)原來(lái)是這樣的。每一欄用了單獨(dú)三個(gè)變量直接去綁定:編寫(xiě)的內(nèi)容、是否標(biāo)準(zhǔn)的標(biāo)志、不標(biāo)準(zhǔn)提示語(yǔ)。我是一個(gè)懶人啊,在我畫(huà)了兩個(gè)瓢以后,就很煩(一直在那復(fù)制變量,在那改來(lái)改去),這些個(gè)變量都是差不多一個(gè)意思。為啥讓我重復(fù)在復(fù)制,修改呢?
明顯每欄有相同項(xiàng)啊,對(duì)不對(duì),一個(gè)是內(nèi)容,一個(gè)狀態(tài),一個(gè)是錯(cuò)誤提示語(yǔ)啊,咆哮!!!
這時(shí)候,我想起了書(shū)本上的一句話(huà): "早重構(gòu),常重構(gòu)"
我已經(jīng)安奈不住我那顆懶惰的心里,因?yàn)橄旅孢€有“狠多狠多”欄,每一行有三個(gè)類(lèi)似的變量,我這依葫蘆畫(huà)瓢,這個(gè)星期加班,就在復(fù)制粘貼去了。我是要上進(jìn),要每天進(jìn)步的人,不能這樣!
我為啥不能將這相同的共性抽象出來(lái)呢?是不咯,這個(gè)時(shí)候,我想起了《葵花寶典》的第一頁(yè)的第一句:“萬(wàn)物皆對(duì)象”,于是本能的告訴我,每一欄看做一個(gè)對(duì)象,只是每欄的值不一樣。然后我就寫(xiě)了一個(gè)”雞肋“(基類(lèi)),代碼如下:
/// <summary>/// 欄 基類(lèi)/// </summary>public class Base: ObservableObject{private string _content;/// <summary>/// 內(nèi)容/// </summary>public virtual string Content{get { return _content; }set{_content = value;RaisePropertyChanged(() => Content);}}private string _errorTip;/// <summary>/// 錯(cuò)誤提示/// </summary>public virtual string ErrorTip{get { return _errorTip; }set{_errorTip = value;RaisePropertyChanged(() => ErrorTip);}}private bool _isError;/// <summary>/// 是否錯(cuò)誤/// </summary>public virtual bool IsError{get { return _isError; }set{_isError = value;RaisePropertyChanged(() => ErrorTip);}}} 復(fù)制代碼virtual是為了讓子類(lèi)能夠重寫(xiě)get和set(如果有需求的話(huà),為后面擴(kuò)展做準(zhǔn)備),然后字段從3個(gè)變到了1個(gè)了。
/// <summary> /// 修改說(shuō)明欄 /// </summary> public class EditDescription : Base { } private EditDescription _editDescriptions; /// <summary> /// 修改說(shuō)欄綁定變量 /// </summary> public EditDescription EditDescriptions {get { return _editDescriptions; }set{_editDescriptions = value;RaisePropertyChanged(() => EditDescriptions);} }// 其他的一樣,我就不多寫(xiě)了 復(fù)制代碼那,我們來(lái)算一下賬,原先的變量,每一欄有3個(gè)變量,一個(gè)變量有6行代碼的話(huà),假如我這個(gè)有100欄,就是:
重構(gòu)前: 100(欄)x3x6 = 1800 行代碼 (阿西吧!!!)。
重構(gòu)后: 100(欄)x1x6 = 600 行代碼 。
小學(xué)算數(shù): 1800 - 600 = 1200 (1200行,你說(shuō)干點(diǎn)啥不好啊)
那秀兒們算下,你花這么多時(shí)間,在那復(fù)制粘貼,不敢去動(dòng)前輩們的代碼,還是勇敢一點(diǎn)呢?
然后是不是感覺(jué)到一個(gè)繼承就簡(jiǎn)單了很多呢,這只是一個(gè)面向?qū)ο蟮暮?jiǎn)單運(yùn)用,就讓我們少寫(xiě)了這么多代碼。
前輩和我說(shuō),寫(xiě)代碼就像練武功,就像你會(huì)了“九陽(yáng)神功”或者"吸星大法",學(xué)其他武功看一眼就會(huì)。也就是說(shuō),當(dāng)你理解了面向?qū)ο笠院竽?#xff0c;你自然而然的就會(huì)寫(xiě)出很精簡(jiǎn)的代碼了。阿西吧,又扯遠(yuǎn)了。
變量好了,抬頭一看函數(shù),我的臉便有點(diǎn)抽搐,啊!!這函數(shù)有毒!函數(shù)是這樣的:
// 此處函數(shù)用來(lái)設(shè)置每一欄報(bào)錯(cuò)時(shí)邊框變紅private void SetValidateFlag(){// 綁定的實(shí)體類(lèi)判斷狀態(tài)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;}// 此處省略一萬(wàn)個(gè)if,每個(gè)欄都有一個(gè)if} 復(fù)制代碼然后大家懂的嘛,在我改了兩欄以后,我又耐不住性子了。再一看,感覺(jué)似曾相識(shí)燕歸來(lái)的感覺(jué)啊!有沒(méi)有,每個(gè)if中都有三個(gè)類(lèi)似的東西。我那個(gè)心啊,又忍不住悸動(dòng)了起來(lái),像是等初戀的感覺(jué),想她來(lái),來(lái)了又不知道要干哈。然后我發(fā)現(xiàn)其實(shí)if中判斷的就是每欄的狀態(tài),括號(hào)里面是對(duì)控件欄的設(shè)置。然后想嘛,能不能搞個(gè)類(lèi)似循環(huán)的東西,只要寫(xiě)一個(gè)for就好了呢。
思考以后,是這樣的,我把控件也變成了欄的一個(gè)屬性了,這樣if判斷里面就都是判斷一個(gè)類(lèi)了。代碼就變成了這樣:
public class Base: ObservableObject{/// <summary>/// 模塊控件(新增)/// </summary>public object Control { get; set; }//其他的和上面的Base一樣} 復(fù)制代碼然后 SetValidateFlag() 函數(shù)就變成了這樣:
/// <summary>/// 設(shè)置校驗(yàn)界面效果/// </summary>private void SetValidateFlag(){// listBase 所有欄實(shí)體集合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;}}} 復(fù)制代碼好了嘞,好好的一個(gè)if的葫蘆瓢給咱給整沒(méi)了。這時(shí)候我們來(lái)算算我們這個(gè)重構(gòu),省了多少事。老樣子:
原先的一個(gè)if算5行代碼,我這個(gè)有100欄,就是:
重構(gòu)前: 100(欄)x 5 = 500 行代碼 (全是if啊)。
重構(gòu)后: 我數(shù)了一下,沒(méi)有錯(cuò)的話(huà)應(yīng)該是:14行代碼 。
重構(gòu)一下以后,變量得到了減少且對(duì)外統(tǒng)一。感覺(jué)一顆心得到了小小滿(mǎn)足,感覺(jué)靈魂得到了升華,不知道是自己太容易滿(mǎn)足,還是代碼世界里給我的成就感。感覺(jué)“乾坤大挪移”瞬間上了兩層。
這就是我在寫(xiě)代碼的時(shí)候一個(gè)小小的重構(gòu)思路,希望能夠幫助到大家一點(diǎn)。然后這個(gè)是我的Github,如果有幫助到大家的項(xiàng)目,可以給我點(diǎn)個(gè)star, 小生在這邊謝謝啦!!!
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
- 上一篇: 【前端基础进阶】JS-Object 功能
- 下一篇: 以当天日期时间,打包目录