“硬核”代碼重構

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

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

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

簡單介紹一下項目,項目就是一個客戶端小工具用來審核編寫遞交的說明是否規范。這里說下,面向對象是一種思想,和語言無關。只要是面向對象語言,無論你是C#、Java、TypeScript、Python,都是可以用這種思想重構的。

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

前輩已經完成一些欄的校驗,我的任務是完成剩下欄:寫正則表達式,然后在不標準的時候提示就好了,是不是覺得根本沒有必要重構,依葫蘆畫瓢就好了在我拿到代碼的時候,是這樣的代碼:

// 下面變量是和界面綁定的變量,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);}}// 這里隨便舉了兩欄的變量,后面還有若干欄。
復制代碼

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

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

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

我已經安奈不住我那顆懶惰的心里,因為下面還有“狠多狠多”欄,每一行有三個類似的變量,我這依葫蘆畫瓢,這個星期加班,就在復制粘貼去了。我是要上進,要每天進步的人,不能這樣!

我為啥不能將這相同的共性抽象出來呢?是不咯,這個時候,我想起了《葵花寶典》的第一頁的第一句:“萬物皆對象”,于是本能的告訴我,每一欄看做一個對象,只是每欄的值不一樣。然后我就寫了一個”雞肋“(基類),代碼如下:

    /// <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, 小生在這邊謝謝啦!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/280153.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/280153.shtml
英文地址,請注明出處:http://en.pswp.cn/news/280153.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

上傳jar包到nexus私服

進入maven管理頁面&#xff0c;登錄管理員賬號 完成后可以進入對應目錄下查看pom依賴 通過maven的方式depoly 在maven的conf/setting.xml 配置nexus私服的管理賬號 在servers標簽下添加server <server><id>nexus-snapshots</id><username>repouser<…

手把手教你寫高質量Android技術博客,畫圖工具,錄像工具,Markdown寫法

前言 作為程序員&#xff0c;寫博客是一件很有意義的事情&#xff0c;可以加深自己對技術的理解&#xff0c;可以結交更多的朋友&#xff0c;記錄自己的技術軌跡&#xff0c;而且分享可以讓更多的人從中受益&#xff0c;獨樂樂不如眾樂樂嘛。 但是要寫好博客也不是件容易的事&a…

【Android】RxJava的使用(四)線程控制 —— Scheduler

前言 經過前幾篇的介紹&#xff0c;對RxJava對模式有了一定的理解&#xff1a;由Observable發起事件&#xff0c;經過中間的處理后由Observer消費。&#xff08;對RxJava還不了解的可以出門左拐&#xff09;之前的代碼中&#xff0c;事件的發起和消費都是在同一個線程中執行&am…

sed: -e expression #1, unknown option to `s'解決辦法

報錯如下&#xff1a; sed: -e expression #1, char 13: unknown option to s 需要替換的行為&#xff1a; monitor.urlhttp://192.168.25.100:8443/rest 查詢資料得知&#xff0c;報錯是因為替換的字符串包含有分隔符/ 所以這行改一下分隔符就可以解決問題了 改成感嘆號!或者|…

Linux常用開發環境軟件-Redis安裝(docker環境下)

linux&#xff0c;docker安裝RabbitMQ版本 1、從docker官網倉庫下載安裝RabbitMQ鏡像 官網地址&#xff1a;https://hub.docker.com/ docker pull redis:4.0.8  //后面是版本,Tag Name 2、啟動Docker Redis鏡像 docker run -d -p 6379:6379 redis:4.0.8  啟動鏡像&#xff…

以當天日期時間,打包目錄

#備份/data目錄#!/bin/bash DATEdate %Y-%m-%d-%H:%M:%S tar cvf /mnt/resource/script/prod_master_data.$DATE.tar.gz /data[root111 script]# ll total 2536 -rw-r--r-- 1 root root 2590720 Feb 22 21:46 prod_master_data.2019-02-22-21:46:53.tar.gz轉載于:https://blog.…

lvs+keepalived詳解

常用軟件安裝及使用目錄 資源鏈接&#xff1a;https://pan.baidu.com/s/15rFjO-EnTOyiTM7YRkbxuA 網盤分享的文件在此 官網&#xff1a;http://www.linuxvirtualserver.org/index.html 中文資料 LVS項目介紹 http://www.linuxvirtualserver.org/zh/lvs1.html …

微信自動打卡

要有第二臺安卓 手機&#xff0c;打開usb、adb調試&#xff0c;永不鎖屏&#xff0c;永不休眠&#xff0c;手機安裝了微信并至少成功登陸過一次&#xff0c; 一臺不關機的電腦&#xff0c;手機連接電腦&#xff0c;Appium服務器保持啟動&#xff0c;在開始菜單 設定好任務計劃程…

利用反射做類參數的校驗

需求描述 業務需求描述&#xff1a;對webservice接口參數校驗 代碼實現 /*** 字符串長度校驗* * param str* param len* return 合法(true),不合法(false)*/public static boolean check(String str, int len) {if (null ! str && str.length() > len) {return fals…

跨域的四種方式

本文主要是關于跨域的幾種方式&#xff0c;關于什么是跨域這里就不多說了&#xff0c;寫這個也是為了記住一些知識點的。 一. jsonp jsonp的跨域方式很容易理解&#xff0c;頁面的的每一個script標簽瀏覽器都會發送get請求獲取對應的文本資源&#xff0c;獲取到了之后&#xff…

Linux之read命令使用

ead命令&#xff1a; read 命令從標準輸入中讀取一行&#xff0c;并把輸入行的每個字段的值指定給 shell 變量 1&#xff09;read后面的變量var可以只有一個&#xff0c;也可以有多個&#xff0c;這時如果輸入多個數據&#xff0c;則第一個數據給第一個變量&#xff0c;第二個數…

python之路day10-命名空間和作用域、函數嵌套,作用域鏈、閉包

楔子 假如有一個函數&#xff0c;實現返回兩個數中的較大值&#xff1a; def my_max(x,y):m x if x>y else yreturn mbigger my_max(10,20)print(bigger) 之前是不是我告訴你們要把結果return回來你們就照做了&#xff1f;可是你們有沒有想過&#xff0c;我們為什么要把結…

hive(II)--sql考查的高頻問題

在了解別人hive能力水平的時候&#xff0c;不管是別人問我還是我了解別人&#xff0c;有一些都是必然會問的東西。問的問題也大都大同小異。這里總結一下我遇到的那些hive方面面試可能涉及的問題 1、行轉列&#xff08;列轉行&#xff09; 當我們建設數據倉庫時&#xff0c;我們…

java概述

一、java平臺無關&#xff1a;jvm二、java健壯語言&#xff1a;無指針&#xff0c;語法上無指正&#xff0c;無內存申請與釋放。 三、java核心機制而&#xff1a; jvmjava垃圾收集機制 GC四、java運行過程&#xff1a;源程序&#xff08;.java&#xff09;——》java編譯器——…

時間間隔

計算當前時間與上次執行時間的時間間隔。 NSTimeInterval timetravel [[NSDate date]timeIntervalSinceDate:self.lastPlaySoundDate];if (timetravel<3.0) {DLog("時間太短&#xff0c;。。");}self.lastPlaySoundDate [NSDate date]; 轉載于:https://www.cnb…

.Net+MySQL組合開發(二) 數據訪問篇

一、建立數據庫、表、添加數據這里我們使用圖形化操作的SQL Manager 2005 Lite for MySQL來建立數據&#xff0c;它的操作界面非常類似OFFICE軟件&#xff0c;使用方便、很容量上手、下面開始建立數據庫及表單擊"Creat New DataBase"&#xff1a;新建DB輸入密碼&…

Git vs SVN

一、Git vs SVN Git 和 SVN 孰優孰好&#xff0c;每個人有不同的體驗。Git是分布式的&#xff0c;SVN是集中式的這是 Git 和 SVN 最大的區別。若能掌握這個概念&#xff0c;兩者區別基本搞懂大半。因為 Git 是分布式的&#xff0c;所以 Git 支持離線工作&#xff0c;在本地可以…

.net api 和java平臺對接技術總結

這兩天 一直和京東對接接口&#xff0c;我們用.net api 提供接口&#xff0c;對方用java調用&#xff0c;本來沒什么問題&#xff0c;但是對方對數據安全要求特別嚴&#xff0c;要驗簽&#xff0c;于是噩夢開始了。 1、在傳輸的時候&#xff0c;約定傳輸格式&#xff1a; HttpW…

Burpsuite學習(4)

2019獨角獸企業重金招聘Python工程師標準>>> burpsuite spider模塊通過跟蹤 HTML 和 JavaScript 以及提交的表單中的超鏈接來映射目標應用程序&#xff0c;它還使用了一些其他的線索&#xff0c;如目錄列表&#xff0c;資源類型的注釋&#xff0c;以及 robots.txt 文…

Git刪除分支/恢復分支

這是https://www.cnblogs.com/utank/p/7880441.html的方法&#xff0c;雖然很老現在有點不一樣&#xff0c;但總體還是能用的。 總結就是兩種方法 1.用commit的id恢復 2.用reflog的頭指針恢復 ?刪除一個已被終止的分支 如果需要刪除的分支不是當前正在打開的分支&#xff0c;使…