程式碼重構意義和方法
一、什麼是重構
重構就是通過調整程式程式碼,但並不改變程式的功能特徵,達到改善軟體的質量、效能,使程式的設計模式和架構更趨合理,更容易被理解,提高軟體的擴充套件性和維護性。
二、為什麼要程式碼重構
需求的不斷變更是重構的最根本原因,而且重構是每一個開發人員都要面對的功課。
程式碼架構最初的設計也是經過精心的設計,具有良好架構的。但是隨著時間的推移、需求的劇增,必須不斷的修改原有的功能、追加新的功能,還免不了有一些缺陷需要修改。為了實現變更,不可避免的要違反最初的設計構架。經過一段時間以後,軟體的架構就千瘡百孔了。bug越來越多,越來越難維護,新的需求越來越難實現,最初的程式碼構架對新的需求漸漸的失去支援能力,而是成為一種制約。最後新需求的開發成本會超過開發一個新的軟體的成本,這就使這個app的生命走到了盡頭。
程式碼重構就能夠最大限度的避免這樣一種現象。系統發展到一定階段後,使用重構的方式,不改變系統的外部功能,只對內部的結構進行重新的整理。通過重構,不斷的調整系統的結構,使系統對於需求的變更始終具有較強的適應能力。
三、通過程式碼重構可以達到以下的目標
2、使程式碼更被其他人所理解
3、幫助發現隱藏的程式碼缺陷
4、從長遠來看,有助於提高程式設計效率,增加專案進度(進度是質量的敵人,質量是進度的朋友)
三、何時需要程式碼重構
1、模糊的不具有任何意義的方法名。
-(void)Ping:(NSString*)str;
重構為:
/**
* 初始化並啟動ping
*
* @param strProxyServer 要ping的伺服器
*/
-(void)autoPingProxyServer:(NSString*)strProxyServer
{
}
2、臃腫的類 。
3、長方法 。
4、大量的傳參。
-(void)studentRegister:(NSString *)school name:(NSString *)name class:(NSString *)class age:(int)age
{
}
重構為:
-(void)studentRegister:(StudentModel *)model
{
}
5、模糊的方法名。
-(void)Ping:(NSString*)str;
改為:
-(void)autoPingProxyServer:(NSString*)strProxyServer;
6. 現有的程式碼對它要實現的功能顯得過於複雜,並且你分析過它。
7. 修改後的程式碼遠比現存的程式碼邏輯要清晰。
8. 有足夠的時間,人手,財力來支援對專案進行迴歸測試。
9. 現有的程式碼陳舊無效率。
10. 無人認領的,寫的很爛的程式碼都屬於此類。
11. 程式碼禁區。這部分程式碼只有一個人可以修改,而且修改可能帶來更大的隱患。
四、哪些情況不需要考慮程式碼重構
1. 邏輯看起來過於複雜,沒時間去分析梳理。
2. 不理解為什麼前任程式設計師要這樣編寫。
3. 負責的是一個很重要的系統,而且時間很緊。
4. 團隊的新成員,或者開發者新接觸的語言
五、重構的具體方法
正如上面提到的,像“臃腫的類”(xmppmanager.h)這種程式碼臭味應該將原有類中的方法和屬性移動到適當數目的新類中去。舊類中對應新類的方法和屬性應該被移除。另外,有時候一些類過於臃腫是因為它包含了被其他類使用本應該是其他類的成員方法的成員方法。這些方法也應該被遷移到合適的類中。
3、分離條件
許多時候,一個方法很長是因為包含好幾個分支語句(if-else)。這些分支條件可以被提取和移動到幾個單獨的方法中。這確實能大大改善程式碼可讀性和可理解性。
If(date.before(monday) || date.after(friday) )
{
total=number*_rate+_fridaycharge;
}
else
{
total=number*_fridayrate;
}
重構為:
if(notFriday(date))
{
total = mondaytotal(number);
}
elser
{
total = fridaytotal (number);
}
-(bool)notFriday(NSDate *)date
{
return date.before(monday) || date.after(friday);
}
-(void)mondaytotal(int)number
{
return number*_rate+_fridaycharge;
}
-(void)fridaytotal(int)number
{
return _fridaycharge;
}
4、引入引數物件/保留全域性物件
在我做程式碼審查時發現另外一個很常見的情況 - 好幾個引數被傳入方法。問題主要與需要從已有方法中增加或者移除一個方法引數有關。在這種場景,建議將相關方法引數組成一個物件(引入引數物件),讓方法傳遞這些物件而不是每個單獨的引數。
5、用符號常量替換無意義數字
對於有意義的並且到處被使用的字面常量,應該為它們分配一個命名常量。這能大大增強程式碼可讀性和可理解性。
If(iosSystemversion >7.)
重構為:
#define iosSystemversion7 7 //ios系統為7
If(iosSystemversion > iosSystemversion)
6、重新命名方法
正如上面提到的,模糊不清的方法名會影響程式碼的可使用性。這些模糊不清的名稱應該重新命名為有意義的可能與業務術語有關的名稱,來幫助開發者通過業務上下文更好地理解程式碼。
-(void)function(nsstring *)str; //擷取string
-(void)trimstring(nsstring *)str; //擷取string
7、記憶體優化
檢查工程的記憶體使用情況,及時Release。
8、去除硬編碼,將文案統一至模組化的巨集定義檔案
將一些通過的文案,常用的文案統一便寫到巨集定義檔案
#define ASK_CREATEQUESTION @" "
重構為:
#define ASK_HOSTURL @"/"
#define ASK_CREATEQUESTION [email protected]""
六、當重構沒有現成的明顯的方向時,我們可以遵循下面的原則
1、程式碼規範
a.圖片用英文名:例如:ToolView_Emotion_HL.png
錯誤: 確定.png, [email protected]
b.程式碼註釋規範。 例如: int age;//年齡
c.巨集定義規範(涉及到全域性的,環境變化的)。
例如:#define PACHAT_ENVIRONMENT 1 //0:int 開發環境 1:stg 測試環境 2:prd 生產環境
d.類名,方法名,變數名命名規範,要有意思,最好用英語。
例如:
#pragma mark -
#pragma mark 查詢公眾號
e.log資訊提交svn時要刪除
f.冗餘程式碼要刪除(廢棄的方法、變數名,註釋掉的程式碼快)
g.新建資料夾要在相應的工程目錄資料夾裡面新建
2、當屬性、方法或類存在任何的需要複用的意向時,歸納提煉它們。
3、不要低估小方法對程式碼整潔的作用。使用小方法能讓你節省很多筆墨。
4、用封裝控制可見度。
5、消除依賴。
6、簡化構造方法——即使這樣做會使程式碼變複雜。
7、不確定時,將計算操作移入到這些資料的所有者物件裡,或將資料移動到執行計算操作的物件裡。
8、使用小物件,鬆耦合,避免大物件,高聚合。
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//TODO:大量的業務邏輯處理
}
重構為:
- (void)dealwithphotoInfo:(NSDictionary *)info
{
//TODO: 具體的業務邏輯處理
….
}
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSMutableDictionary *dicinfo = [NSMutableDictionary dictionaryWithDictionary:info];
[dicinfo setObject:[NSNumber numberWithInt:picker.sourceType ] forKey:@"camreSourceType"];
[self performSelector:@selector(dealwithphotoInfo:) withObject:dicinfo afterDelay:0.1]; // 延時處理圖片壓縮和儲存
[picker dismissViewControllerAnimated:YES completion:nil];
}
9、使用代理物件,模擬物件和輔助物件來隔離網路,資料庫,檔案和使用者介面。
10、不確定時,儘量在model裡新增程式碼,必要時才往controler新增程式碼。view裡新增的都應該是便捷功能和簡寫方法,但不要侷限於此。
七、如何降低重構的風險
1. 使用自動化的迴歸測試,快速的驗證你的修改。這非常重要,如果沒有準備自動化測試,你應該在做任何修改前建好它。
2. 儘量讓你的重構處於很短的開發週期,產品更新發布週期也儘可能短。
3. 把你重構的程式碼和其它程式隔離開,這樣能讓你更容易找到出問題的地方。
4. 為你的重構活動準備測試計劃,包括迴歸測試,功能測試,反向測試,負載測試,效能測試和使用者確認測試。
5. 投入全部精力來研究其中的邏輯,不要分心做其它事情。
6. 在需要的地方使用設計模式。不要為了設計模式而增加設計模式。設計模式應該用在合適的時間和合適地方。
相關推薦
程式碼重構意義和方法
摘要:很多人認為重構浪費時間,影響專案進度,其實重構不僅可以讓我們的程式碼更加強壯而且還可以加快我們的專案進度。就和我們蓋一個高樓大廈一樣,我們的架構和地基越好,我們的樓房會越堅固和牢靠。 一、什麼是重構 重構就是通過調整程式程式碼,但並不改變程式的功能特
重構程式碼的思路和方法1
<div class="markdown_views"> <h3 id="重構前需要考慮"><a name
程式碼重構之法——方法重構分析
# 程式碼重構之法——方法重構分析 ## Intro 想要寫出比較優秀的程式碼,需要時刻警惕程式碼中的壞味道,今天想寫一篇文章介紹一下如何分析你的方法是不是需要考慮重構 一個方法通常有三個部分組成,輸入(Input),輸出(Output),方法體(Method Body),我們就從這三個方面來分析一個方
少說話多寫程式碼之Python學習040——類02(類的函式和方法 )
在類裡定義函式時的self引數,其實是方法和函式的區別。在類裡定義方法時,一般都在方法里加一個預設的引數,可以是,a,c,d的。但是約定俗成就統一叫self。self表示的是 這個類的當前例項,一個類有多個例項,那麼它屬於自己所屬於的例項,不會存在例項寧缺的self會指向例項陳皮皮。 這裡比價特
java獲取某段程式碼執行時間和js獲取方法執行時間
java獲取某段程式碼執行時間和js獲取方法執行時間 java // 測試執行時間 long startTime = System.currentTimeMillis(); 程式碼段...... // 結束時間 long endTime = Syst
git分支(存在意義和使用方法)
Git分支簡介 Git分支是由指標管理起來的,所以建立、切換、合併、刪除分支都非常快,非常適合大型專案的開發。 在分支上做開發,除錯好了後再合併到主分支。那麼每個人開發模組式都不會影響到別人。 分支使用策略: 主分支(預設建立的Master分支)只用來分佈重大版本(對
Notepad++強大的程式碼補全和程式碼提示功能的方法
最近寫專案,經常要開啟一些檔案去修改一些程式碼段。那麼我的專案都是使用ied大型編輯器去寫的,每次修改檔案,哪怕是一個標點都要用一分鐘時間去開啟軟體。當然,後來我也考慮到使用記事本,但總感覺不是很爽。 於是,我發現了一款輕快小巧功能強大的編輯器-Notepad++; 先來
javaSE (三十五)多執行緒 ( 多執行緒實現方法和區別、同步程式碼塊和方法(執行緒安全))
主要還是熟悉api,熟悉方法,簡單,需要多實踐 1、 多執行緒實現方法和區別: 多執行緒實現的兩種方法: 1)類繼承Thread類或實現Runnable介面,重寫run()方法 2)建立Thread的子類物件(需要開幾個執行緒就建立幾個物件,可建立匿名內部類) 3)子類
撩課-JavaWeb之Dao程式碼重構存在的問題與抽取DML方法
存在的問題 在DAO當中執行的儲存方法,更新方法,刪除這些DML操作有太多重複程式碼 圖示: 重構程式碼原則 同一個類中 在一個類當中有多個方法當中有太多相同的程式碼 不同的地方通過引數傳遞進去 把它們抽到一個方法當中 不同類中 不同類當中有共同的
聊聊HTML靜態頁面編碼規範和前端程式碼重構
彪悍的人生不需要解釋,彪悍的程式碼不需要註釋!作為程式猿,工作中我們都要涉及到與團隊合作,為了讓團隊合作的效率提高,我們在寫程式碼的時候都應該講究規範,比如註釋,html程式碼的嵌入規則,c
方法鎖、物件鎖、類鎖的意義和區別
synchronized用來處理多個執行緒同時訪問同一個類的一個程式碼塊、方法,甚至這個類。 (1)修飾程式碼塊時,需要一個reference物件作為鎖的物件。 (2)修飾方法時,預設是當前對線作為鎖的
談一談修改程式碼時加註釋的原則和方法
暮鼓集 行走集 原作於2008年06月01日,軟體部培訓稿 我們修改程式碼時少不了要加一些註釋,這基本的原則是“言簡意賅”,只要做到大家能看懂,在版本比較工具(BC及VSS)中能一目瞭然,這就可以了。 下面介紹一些方法供大家參考:
Android NDK(JNI)學習總結一:Java程式碼中申明native函式-Java呼叫C函式,並在C函式中訪問java類和方法、屬性
本文不涉及android-ndk開發環境搭。 步驟一:新建一個APP,名稱為HelloJNI,然後定義一個類(將會在native程式碼中呼叫和訪問該類): package com.example.hellojni; public class JNITe
Java快取Ehcache-核心類和方法介紹及程式碼例項
Ehcache中核心類和方法 EhCache裡面有一個CacheManager型別,它負責管理cache。Cache裡面儲存著Element物件,Element必須是key-value對。Cache是實際物理實現的,在記憶體中或者磁碟。這些元件的邏輯表示就是下面即將要討論
類中靜態方法和靜態變數,靜態程式碼塊,構造方法,以及被@PostConstruct修飾的方法執行順序
第一種:當直接呼叫(沒有new物件)靜態方法時候:程式碼塊(靜態變數按照順序)就執行—–方法執行。 第二種建立物件:執行父類靜態程式碼—-執行子類的靜態程式碼—-執行父類構造方法—–執行子類的構造
git提交到HEAD detached導致程式碼丟失;找回方法和分析
背景 今天線上出現bug, 在切換到舊版本的時候,由於誤操作導致原生代碼丟失,找回巨費時,特記錄如下; bug產生原因 首先在master分支上開發,線上出現bug且回到舊版本的tag,這時master分支上有一部分程式碼修改但未提交。 當前在master上:執行git status 有未提交的程式碼
程式碼中動態和佈局檔案中靜態改變Edittext游標樣式方法
這兩種修改游標樣式的方法各有優缺點,我會在後面說明。建議使用第一種 1、佈局檔案中修改Edittext游標樣式(常用) drawable下,建立游標樣式檔案:edittext_cursor_style <?xml version="1.0" enco
java類載入和例項化:靜態程式碼塊、初始化程式碼塊、構造方法的執行順序
java中第一次例項化一個物件時,靜態程式碼塊、初始化塊、屬性的初始化、構造方法,再加上如果父類也有這些東西,天,到底執行順序是什麼? 來一段程式碼試一試就知道了: public class LoadingTest { public static void main(
Java中對類中的屬性使用set/get方法的意義和用法
經常看到有朋友提到類似:對類中的屬性使用set/get方法的作用?理論的回答當然是封閉性之類的,但是這樣對我們有什麼作用呢?為什麼要這樣設計?我直接使用屬性名來訪問不是更直接,程式碼更簡潔明瞭嗎?下面我們就來介紹下為什麼要使用set/get方法來代替直接訪問屬性
函數屬性和方法:length和prototype
scrip spa ont pan div blog 屬性 col 方法 ECMAScript中的函數是對象,因此函數也有屬性和方法。每個函數都包含兩個屬性:ength和prototype。 其中, length屬性表示函數希望接收的命名參數的個數 . function