軟件配置管理複習

軟件配置管理程序員

第1章    軟件配置管理概念與目標算法

  1. 軟件配置管理(Software Configuration Management, SCM)

(1)    定義(多個):數據庫

l  軟件配置管理是指一套管理軟件開發和維護過程當中所產生的各類中間軟件產品的方法和規則,它是控制軟件系統演變的學科。編程

l  軟件配置管理是一組針對軟件產品的追蹤和控制活動,它貫穿於項目生命週期的始終,並表明着軟件產品接受各項評審。數組

l  軟件配置管理是貫穿於整個軟件過程當中的保護性活動,它被設計用來:(1) 標識變化;(2) 控制變化;(3) 保證變化被適當的發現;(4) 向其餘可能有興趣的人員報告變化。安全

(2)    目標:服務器

l  軟件配置管理的各項工做是有計劃進行的。網絡

l  被選擇的項目產品獲得識別,控制而且能夠被相關人員獲取。session

l  已識別出的項目產品的更改獲得控制。架構

l  使相關組別和我的及時瞭解軟件基準的狀態和內容。

(3)    目的:使錯誤降爲最小並最有效地提升生產效率。

  1. 最終軟件版本產品

最終軟件版本產品是文檔、程序和數據的集合,是軟件生產商交付給客戶的軟件產品,是用戶可以直接使用的軟件產品。

  1. 軟件配置

軟件配置是一個軟件產品在生存期各個階段的不一樣形式(記錄特定信息的不一樣媒體)和不一樣版本的程序、文檔及相關數據的集合,或者說是配置項的集合。

  1. 軟件配置項(Software Configuration Item,SCI)

l  軟件配置是一個集合,該集合中的每個元素稱爲該軟件產品軟件配置中的一個配置項。

l  軟件配置項是軟件配置管理的對象,一個軟件配置項是項目中一個特定的、可文檔化的工做產品集。

 

  1. 基線(Baseline)

(1)    概念

l  基線是指一個(或一組)配置項在項目生命週期的不一樣時間點上經過正式評審而進入正式受控的一種狀態。

l  基線是已經正式經過複審和批准的某規約和產品。

l  通過正式評審和審計,並被批准後的階段性軟件工做產品,稱爲軟件配置管理中的一根基線。

(2)    分類

l  功能基線:

  • 在系統分析和軟件定義階段結束時,通過正式評審和批准的系統設計規格說明中對被開發軟件系統的規格說明;
  • 通過項目委託單位和項目承辦單位雙方簽字贊成的協議書或合同中所規定的對被開發軟件系統的規格說明;
  • 由下級申請及上級贊成或直接由上級下達的項目任務書中所規定的對待開發軟件系統的規格說明。

l  指派基線:又稱爲分配基線,指在軟件需求分析階段結束時,通過正式評審和批准的軟件需求的規格說明,指派基線是最初批准的指派配置標識。

l  產品基線:指在軟件組裝與系統測試階段結束時,通過正式評審的批准的有關所開發的軟件產品的所有配置項的規格說明,產品基線是最初批准的產品配置標識。

 

  1. 軟件配置控制委員會(Software Configuration Control Board, SCCB,簡稱CCB)

l  負責管理軟件配置項變動的組織。

l  具體責任以下:

  • 評估變動;
  • 批准變動請求;
  • 在生命週期內規範變動申請流程;
  • 對變動進行反饋;
  • 與項目管理層溝通。

第2章    軟件配置管理角色與過程

  1. 1.     軟件配置管理角色及職責

(1)    項目經理(Project Manager,PM)

l  項目經理是整個軟件研發活動的負責人,他根據軟件配置控制委員會的建議批准配置管理的各項活動並控制它們的進程。

l  其具體職責爲如下幾項:

  • 制定和修改項目的組織結構和配置管理策略;
  • 批准、發佈配置管理計劃;
  • 決定項目起始基線和開發里程碑;
  • 接受並審閱配置控制委員會的報告。

(2)    配置控制委員會(Configuration Control Board,CCB)

l  負責指導和控制配置管理的各項具體活動的進行,爲項目經理的決策提供建議。

l  其具體職責爲如下幾項:

  • 定製開發子系統;
  • 定製訪問控制;
  • 制定經常使用策略;
  • 創建、更改基線的設置,審覈變動申請;
  • 根據配置管理員的報告決定相應的對策。

(3)    配置管理員(Configuration Management Officer,CMO)

l  根據配置管理計劃執行各項管理任務,按期向CCB提交報告並列席CCB的例會。

l  其具體職責包括如下幾項:

  • 軟件配置管理工具的平常管理與維護;
  • 提交配置管理計劃;
  • 各配置項的管理與維護;
  • 執行版本控制和變動控制方案;
  • 完成配置審計並提交報告;
  • 對開發人員進行相關的培訓;
  • 識別軟件開發過程當中存在的問題並擬定解決方案。

(4)    系統集成員(System Integration Officer,SIO)

l  負責生成和管理項目的內部和外部發布版本。

l  其具體職責爲如下幾項:

  • 集成修改;
  • 構建系統;
  • 完成對版本的平常維護;
  • 創建外部發布版本。

(5)    開發人員(Developer,DEV)

l  根據組織內肯定的軟件配置管理計劃和相關規定,按照軟件配置管理工具的使用模型來完成開發任務。

  1. 軟件配置管理基本流程

 

(1)    計劃階段

l  CCB根據項目的開發計劃肯定各個里程碑和開發策略;

l  CMO根據CCB的規劃,制定詳細的配置管理計劃,交CCB審覈;

l  CCB審覈配置管理計劃後交項目經理批准,發佈實施。

(2)    開發和維護階段:

在這一階段中,軟件配置管理活動主要分爲三個層面:

l  主要由CMO完成的管理和維護工做;

l  由SIO和DEV具體執行軟件配置管理策略;

l  變動流程。

核心流程爲:

l  CCB設定研發活動的初始基線;

l  CMO根據軟件配置管理規劃設立配置庫和工做空間,爲執行軟件配置管理作好準備;

l  開發人員按照統一的軟件配置管理策略,根據得到的受權的資源進行項目的研發工做;

l  SIO按照項目的進度集成組內開發人員的工做成果,並構建系統,推動版本的演進;

l  CCB根據項目的進展狀況,審覈各類變動請求,並適時的劃定新的基線,保證開發和維護工做有序的進行。

  1. 3.     軟件配置管理基本活動

 

(1)    制定配置管理計劃

l  步驟:

  • 參加項目規劃
  • 規劃配置管理任務
  • 造成配置管理計劃
  • 評審配置計劃

l  配置管理計劃主要內容:

  • 配置管理組織及其職責
  • 配置管理工具和配置庫的組織結構
  • 配置項標誌和基線定義
  • 變動管理流程
  • 配置審覈和配置狀態統計

(2)    識別和標誌配置項

步驟:

l  將軟件項目中須要進行控制的工做產品定義爲配置項(SCI)。

配置項分爲:

  • 基本配置項:軟件開發者在項目開發過程當中所建立的基本工做單元。
  • 集成配置項:一個集成配置項是基本配置項或其它集成配置項的集合。

 

l  爲每個配置項分配惟一的標誌。

 

注意:配置項標識並非指程序/文檔文件的文件名,而是該程序/文檔做爲一個配置項的標識。

l  創建配置項間的對應關係。

 

可以使用某種模塊互聯語言(Module Interconnection language, MIL)來描述配置項之間的關係。

(3)    搭建配置管理環境

l  配置管理環境是用於進行軟件配置管理的系統環境,其中最重要的是配置管理庫,簡稱配置庫。

l  配置庫存儲配置項 (SCI)、修改請求、變化記錄等,並提供對庫中所存儲文件的版本控制。

l  爲不一樣的開發人員分配不一樣的訪問配置庫的權限。

l  通常需採用配置管理工具來創建配置庫。

l  配置庫中文件的更改是受控的。

(4)    配置項的版本控制

 

l  當開發人員要使用配置庫中的一個文件時,將文件檢出到本身的工做目錄裏,此時該文件在配置庫中被自動鎖定,開發人員處理完該文件後,再將文件檢入到配置庫中(需有修改權限),一個新的版本號自動與文件相關聯,文件解鎖。

l  配置庫的檢入檢出和版本控制機制解決了軟件開發中的兩個重要問題:

  • 訪問控制:保證具備相應權限的人員才能修改配置項。
  • 並行控制:保證不一樣人員同時對某配置項進行的修改不會互相覆蓋。

l  軟件產品不一樣類型的版本的特性和所包含的配置項應被明確描述,保證可根據要求將配置項組合生成適用於不一樣應用環境的正確的軟件產品版本。

(5)    基線變動管理

l  變動請求

 

l  變動評估

 

l  變動批准/拒絕

根據評估結果對變動做出決策:

  • 直接實現變動
  • 掛起或延遲變動
  • 拒絕變動
  • 對於批准的變動,要肯定其實現進度
  • 當即實現變動
  • 特定的日期實現變動
  • 在軟件另外的版本中實現

l  變動實現

 

(6)    配置審覈

l  配置管理活動審覈:確保全部配置管理活動符合已批准的軟件配置管理規程。

l  基線審覈:審覈基線配置項的完整性和一致性,從而保證基線配置項可被正確地構造。

  • 配置庫中是否包含了全部計劃歸入的基線?
  • 基線自身的內容是否完整?
  • 編譯全部的源代碼,檢查是否可產生最終軟件產品。
  • 檢查需求、設計與代碼間的一致性。

(7)    配置狀態統計

l  配置管理系統的狀態統計和評估

  • 變動請求的數量。
  • 變動管理活動的執行狀況
  • 配置管理系統存儲量的變化。
  • 配置管理系統在運做中發生異常的次數。

l  配置狀態報告

  • 每次配置的更改被批准或實現時,都會產生一個配置狀態報告,通知相關人員:更改了哪些內容?由誰更改?何時更改?更改會產生哪些影響?
  • 對於大型項目的開發,配置狀態報告很是重要,它促進了人員之間的通訊。
  1. 版本的編號

(1)    數字順序型版本編號

l  普通版本編號

  • 產品的版本號由若干數字組成,數字之間用「.」分隔。一種典型的編號策略以下:

x.y.z,x爲主版本號,y爲特徵版本號,z爲缺陷修復版本號,如V3.10.16。

²  主版本號的增長表示提供給客戶的主要產品功能的加強。

²  特徵版本號的增長表示產品新增了一些特徵或作了一些重要修改。

²  缺陷修復版本號的增長表示在軟件產品上作了一些缺陷修復工做。

  • 文檔編號的具體形式爲英文(或中文)名加上該配置項所在的版本號,例如,詳細說明書是一個配置項,它的某一個版本標識爲「詳細設計說明書V1.0.1」。

l  α和β版本編號

  • 在普通版本編號後面增長一個大寫字符A或者B來分別表示α版本或β版本。例如1.2.4A或1.2.4B。
  • 若是存在屢次的α發佈和β發佈,可在A或B後面添加一個數字來講明發布的次數,例如:1.2.5A1,1.3.0B2。

²  α測試是由公司內部的用戶在模擬實際操做環境下進行的測試。

²  β測試是由軟件的多個用戶在實際使用環境下進行的測試。

(2)    屬性版本編號

l  把版本的重要屬性反映在標識中。能夠包括的屬性有:客戶名、開發語言、開發狀態、硬件平臺、生成日期等。例如:J2SDK.v.l.2.2:10/31/2000-18:00,native threads, jit-122(Jit(Just in Time):Java即時編譯技術)

l  包含的信息豐富,方便了查詢和管理,版本間的關係易於保持,但因爲太複雜,通常只用於軟件組織內部的管理。

第3章    軟件配置管理核心功能

  1. 軟件配置管理與CMM/CMMI

(1)    軟件配置管理是CMM/CMMI二級的一個重要KPA。

(2)    CMM/CMMI將軟件配置管理的活動分爲6個方面

l  SCM過程管理

l  軟件配置標識

l  軟件配置控制

l  軟件配置狀態統計

l  軟件配置審計

l  軟件發佈管理和交付

(3)    在CMM和CMMI中,將配置管理的目的定義爲「創建和維護產品的完整性」。

 

(4)    配置完整性

l  產品完整性:項目提交的工做成果是「產品集合完整、子產品正確」的

l  產品集合完整:產品包含的子產品(配置項)是完整的

l  子產品正確:子產品(配置項)達到了需求要求,知足標準、規程的要求

(5)    三庫管理:三庫的概念源自CMM/CMMI,即開發庫、受控庫和產品庫。配置項在三庫之間遷移,一級比一級的控制更嚴格。

 

l  開發庫:存放開發過程當中須要保留的各類信息,供開發人員專用。

l  受控庫:在軟件開發的某個階段工做結束時,將工做產品存入或將有關的信息存入。

l  產品庫:在開發的軟件產品完成系統測試以後,做爲最終產品存入庫內,等待交付用戶或現場安裝。

  • 按照三庫的思路,軟件開發組平常的工做在開發庫中開展,當工做達到里程碑時,再遷移到受控庫,在受控庫中通過更嚴格的測試後,再上升到產品庫,最後發佈。
  • 在實踐中,三庫經常被實現爲物理上的三庫,而不是經過邏輯的方式來實現,三庫物理隔離帶來的最大問題是配置項失去了歷史可追溯性
  • 實現三庫的指導思想應該是邏輯上獨立,物理上在一塊兒,經過權限與流程的控制來實現配置項在不一樣庫之間的流轉,以及相應角色的人員對相應庫的訪問。
  • 無論是幾個庫,最終都是要提升管理效率和保存工做成果和工做記錄
  1. 軟件配置管理核心功能

(1)    基線管理:每一個基線都將接受配置管理的嚴格控制,對其的修改將嚴格按照變動控制要求的過程進行,在一個軟件開發階段結束時,上一個基線加上增長和修改的基線內容造成下一個基線,這就是「基線管理」的過程。

l  基線具備如下屬性:

  • 經過正式的評審過程創建
  • 基線存在於基線庫中,對基線的變動接受更高權限的控制
  • 基線是進一步開發和修改的基準和出發點
  • 進入基線前,不對變化進行管理或者較少管理
  • 進入基線後,對變化進行有效管理,並且這個基線做爲後繼續工做的基礎
  • 不會變化的東西不要歸入基線
  • 變化對其餘沒有影響的能夠不歸入基線

l  創建基線的好處:

  • 重現性:及時返回並從新生成軟件系統給定發佈版的能力,或者是在項目中的早些時候從新生成開發環境的能力。當認爲更新不穩定或不可信時,基線爲團隊提供一種取消變動的方法。
  • 可追蹤性:創建項目工件之間的先後繼承關係。目的是確保設計知足要求、代碼實施設計以及用正確代碼編譯可執行文件。
  • 版本隔離:基線爲開發工件提供了一個定點和快照,新項目能夠從基線提供的定點之中創建。做爲一個單獨分支,新項目將與隨後對原始項目(在主要分支上)所進行的變動進行隔離。

l  基線、配置、配置項的關係:

 

l  基線管理的步驟:

  • 在開發前肯定基線的「配置」
  • 基線批准前,根據「配置」檢查配置項是否齊備
  • 對各個配置項,確認其版本的正確性
  • 對每一個配置項創建基線標誌
  • 基線變動管理
  • 基線的各種報告和審計信息

(2)    變動管理:在有效標識了配置項並進行了管理以後,如何保證它們在複雜多變的開發過程當中真正處於受控的狀態,並在任何狀況下都能迅速的恢復到任一歷史狀態就要依賴變動管理。

l  缺少有效的變動請求管理會致使的問題:

  • 軟件產品質量低下,對一些缺陷的修正被遺漏
  • 項目經理不瞭解開發人員的工做進展,缺少對項目現狀進行客觀評估的能力
  • 開發人員不瞭解手頭工做的優先級別,可能出現將緊急的事情放在一邊、而工做在通常優先級任務上的狀況
  • 可能錯誤使用和引用已經變動的產品,引發開發工做混亂

l  變動管理的流程:

  • (得到)提出變動請求;
  • 由CCB審覈並決定是否批准;
  • 爲(被接受)修改請求分配人員,提取SCI,進行修改;
  • 提交修改後的SCI,並測試(或者評審);
  • 重建軟件的適當版本;
  • 複審(審計)全部SCI的變化;
  • 發佈新版本。

l  爲了更好的指導變動範圍的影響分析,能夠經過兩種表格來幫助發現受到變動影響的內容,一種是《需求跟蹤表》,一種是《配置項依賴關係表》:

 

(3)    配置庫管理

l  設置版本分支:爲每一個配置項從創建開始就劃分紅3個不一樣的分支:私有分支、集成分支、公共(主幹)分支,讓它們分別對應3類工做空間:

  • 私有分支對應的是開發人員的私有開發空間。除該開發人員外,其餘人員均無權操做該私有空間中的元素。
  • 集成分支對應的是開發團隊的公共空間。凡是要爲同組人員共享的配置項都從該分支得到。該開發團隊擁有對該集成分支的讀寫權限,而其餘成員只有只讀權限。該分支的管理工做由系統集成員及相關指定人員負責。
  • 公共分支對應的是整個軟件開發組織的公共空間。該分支對組織內的全體軟件人員開放只讀權限。該分支的管理工做由系統集成員負責。

l  配置庫的設置:決定配置庫的結構是配置管理活動的重要基礎,通常經常使用的是兩種組織形式:按配置項類型分類建庫和按任務建庫。

l  配置庫的平常工做:配置庫的平常工做是一些事務性的工做,主要保證配置庫的安全性,包括:

  • 對配置庫的按期備份
  • 清除無用的文件和版本
  • 檢測並改進配置庫的性能等

(4)    配置審計:配置審計的主要做用是做爲變動控制的補充手段,來確保某一變動需求已被切實實現。

l  配置審計有兩種:

  • PCA (Physics Configuration Audit):即物理審計,主要是檢查版本是否正確一致,通常由非配置管理人員來進行。

²  配置項是否齊備

²  版本是否齊全

  • FCA (Function Configuration Audit):即功能審計,主要是檢查配置項是否完整,各類過程文檔是否齊備、正確、與需求是否一致,歸結爲兩點,即徹底和齊備,由CMO來進行。

l  配置審計步驟:

  • 由項目經理決定什麼時候進行配置審計工做
  • 質量保證組或項目組的配置管理組制定該項目的配置審計人員
  • 項目經理和配置審計員決定審計範圍
  • 配置審計員準備配置審計檢查單
  • 配置審計員安排時間審計文檔和記錄,審計活動可能涉及到:項目範圍,配置項的入庫(check in)及出庫(check out),評審記錄,配置項的變動歷史,測試記錄,文件的命名,變動請求和版本的編號等。
  • 配置審計員在審計中發現不一致現象,並做記錄
  • 由項目經理負責消除不一致現象
  • 配置審計員驗證全部發現的不一致現象確已獲得解決

(5)    配置狀態報告:根據配置項操做的記錄來向管理者報告軟件開發活動的進展狀況。

l  應着重反映當前基線配置項的狀態,以做爲對開發進度報告的參照。

l  爲了說明項目狀態對變動的狀況也應當進行報告。

l  有時,對配置庫的狀況也進行說明,例如備份次數,磁盤佔用空間等等。只要是關心的信息,都可做爲狀態報告的內容。這些信息進行有效記錄,每每能夠做爲項目度量的重要數據來源。

第4章    軟件配置管理規範與相關文檔

  1. 軟件配置管理計劃

主要內容:

l  人員及職責

l  配置管理軟硬件資源

l  配置項計劃

l  基線計劃

l  配置庫備份計劃

  1. 配置庫管理報告

主要內容:

l  基本信息

l  項目成員的操做權限

l  配置項記錄

l  基線記錄

l  配置庫備份記錄

l  配置項交付記錄

l  配置庫重要操做日誌

  1. 配置項變動控制報告

主要內容:

l  變動申請

l  審批變動申請

l  變動配置項

l  結束變動

  1. 配置狀態報告

主要內容:

l  各份變動請示概要:變動請求號、日期、申請人、狀態、估計工做量、實際工做量、發行版本、變動結束日期

l  基線庫狀態:庫標識、至某日預計庫內配置項數、實際配置項數

l  發行信息:發行版本、計劃發行時間、實際發行日期、說明

l  備份信息:備份日期、介質、備份存放位置

l  配置管理工具狀態

l  配置管理培訓狀態

  1. 配置審計報告

主要內容:

l  配置項狀態統計

l  基線庫基線統計

l  變動統計

l  審計中發現的主要問題

第5章    軟件配置管理工具(5-8)

  1. Microsoft Visual SourceSafe(VSS)

(1)    特色

l  提供了完善的版本和配置管理功能,以及安全保護和跟蹤檢查功能

l  與 Visual Basic、Visual C++、Visual FoxPro 等開發環境以及 Microsoft Office 應用程序集成在一塊兒

l  工做原理簡單

(2)    優勢

l  可以與Visual Studio實現無縫集成,使用簡單

l  提供了歷史版本記錄、變動控制、文件比較、日誌等基本功能

(3)    缺點

l  只支持Windows平臺

l  速度慢、伸縮性差

l  老版本(VSS6.0及之前)不支持並行開發,只支持Check Out – Modify – Check In的管理方式,一個時間只容許一我的修改代碼

l  老版本(VSS6.0及之前)不支持異地開發

  1. Concurrent Versions System(CVS)

(1)    特色

l  CVS採用客戶機/服務器體系結構,代碼、文檔的各類版本都存儲在服務器端,開發者首先從服務器上得到一份複製到本機,而後在此基礎上進行開發。

l  基於「拷貝—修改—合併」的併發控制

  • 客戶端check out後,有文件的一份獨立拷貝。
  • 開發者在本身的工做目錄中修改文件。
  • 如有版本衝突,則使用合併(merge)功能與其餘開發者的修改合併,而後提交(check in)。

l  記錄不一樣版本之間的差異

(2)    優勢(與VSS相比)

l  SourceSafe有的功能CVS全都有,CVS支持併發的版本管理,SourceSafe沒有併發功能。CVS服務器的功能和性能都比SourceSafe高出一籌。

l  CVS服務器是用Java編寫的,能夠在任何操做系統和網絡環境下運行。CVS深受Unix和Linux 的用戶喜好。Borland公司的JBuilder提供了CVS的插件,Java程序員能夠在JBuilder集成環境中使用CVS進行版本控制。

l  CVS服務器有本身專用的數據庫,文件存儲並不採用SourceSafe的「共享目錄」方式,因此不受限於局域網,信息安全性很好。

(3)    缺點(與VSS相比)

l  客戶端軟件,五花八門、參差不齊。Unix和Linux 的軟件高手能夠直接使用CVS命令行程序,而Windows用戶一般使用WinCVS。安裝和使用WinCVS顯然比SourceSafe麻煩很多,這是比較使人遺憾的。  

  1. Subversion(SVN)

(1)    特色(和CVS比較)

l  和CVS的類似性

l  目錄的版本化

l  更加好的文件版本管理(例如對文件拷貝,重命名的處理)

l  提交的原子性

l  元數據的版本化

l  可選的網絡層

l  對文本文件和二進制文件一致的差別比較算法

l  高效的分支(branch)和標籤(tag)操做

l  良好的可維護性

(2)    經常使用的SVN命令

命令名稱

功能

svnadmin create

建立一個新的空的版本庫。

svn add

添加文件、目錄或符號鏈。

svn checkout

從版本庫取出一個工做副本。

svn commit

將修改從工做副本發送到版本庫。

svn copy

拷貝工做副本或版本庫中的文件或目錄。

svn delete

從工做副本或版本庫中刪除一個項。

svn diff

顯示兩個版本或兩個路徑的區別。

svn import

將未歸入版本控制的文件或目錄樹提交到版本庫。

svn info

顯示本地或遠程條目的信息。

svn list

列出版本庫中的目錄內容。

svn lock

鎖定版本庫中的路徑,使得其餘用戶不能向其提交修改。

svn log

顯示提交日誌信息。

svn merge

合併兩個版本中的內容。

svn mkdir

建立歸入版本控制的新目錄。

svn move

移動一個文件或目錄。

svn resolved

刪除工做副本中目錄或文件的「衝突」狀態。

svn revert

撤銷全部的本地修改。

svn status

打印工做副本中文件和目錄的狀態。

svn switch

更新工做副本至同一版本庫中另外一個URL。

svn unlock

解除工做副本或URL的鎖定。

svn update

更新你的工做副本。

  1. 版本控制的數據共享模型

l  Lock-Modify-Unlock Model(加鎖-修改-解鎖)

 

存在問題:

  • 可能致使管理問題,如長期鎖定文件不放
  • 會致使沒必要要的按順序開發
  • 可能致使死鎖

l  Copy-Modify-Merge Model(拷貝-修改-合併)

 

 

 

存在問題:

  • 衝突的產生:

衝突是隨着拷貝-修改-合併方案的產生而帶來的問題。兩個開發者使用拷貝-修改-合併方案編輯同一個文件,而且兩人的修改發生了交疊時就發生了衝突

  • 衝突的解決:

當衝突發生時,開發者會看到一對衝突的修改結果,一般狀況下,必須讓引發衝突的兩我的商議以後,手動選擇保留一組更改。在這裏,版本控制系統只能提示衝突的發生而沒法給出解決建議

  • 衝突的預防:

增長開發者的交流能夠最大限度減小衝突的發生,可是不可能杜絕衝突

l  兩種方案比較與選擇

  • 文本文件(例如源代碼以及用純文本,HTML,TXT等格式保存的文檔):由於其內部結構直觀可知,容易理解上下文,因此用拷貝-合併方案較好。
  • 二進制文件(例如Microsoft Word格式,PDF等格式保存的文檔及圖片,聲音,可執行文件,庫等):內部結構複雜,且不容易理解更改處的上下文,採用鎖定-解鎖方案較好。

代碼味道與重構

  1. 重構

(1)    重構概念

重構是在不改變軟件現有功能的基礎上,經過調整程序代碼改善軟件的質量、性能,使程序的設計和架構更趨合理,進而提升軟件的擴展性和維護性。

(2)    重構意義

l  重構改進軟件設計(Refactoring Improves the Design of Software)

l  重構使軟件更容易理解 (Refactoring Makes Software Easier to Understand)

l  重構幫助找到缺陷 (Refactoring Helps You Find Bugs)

l  重構提升編程速度 (Refactoring Helps You Program Faster)

(3)    重構時機

l  添加功能時重構 (Refactor When You Add Function)

l  修補錯誤時重構 (Refactor When You Need to Fix a Bug)

l  複審代碼時重構(Refactor As You Do a Code Review)

  1. 代碼味道簡介:指程序中存在的一些不良的編程或設計方案。

(1)    類內味道

Measured Smells(可度量的味道)

  • Long Method(過長函數)
  • Large Class(過大類)
  • Long Parameter List(過長參數列)
  • Comments(過多的註釋)

Unneccessary Complexity(沒必要要的複雜性)

  • Speculative Generality(誇誇其談的將來性)

Duplication(重複)

  • Duplicated Code(重複代碼)
  • Alternative Classes with Different Interfaces(殊途同歸的類)

Conditional Logic(條件邏輯)

  • Switch StatementsSwitch驚悚現身)

(2)    類間味道

l  Data(數據)

  • Primitive Obsession(基本類型偏執)
  • Data Class(純稚的數據類)
  • Data Clumps(數據泥團)
  • Temporary Field(使人迷惑的暫時值域)

l  Inheritance(繼承)

  • Refused Bequest(被拒絕的遺贈)
  • Inappropriate Intimacy(狎暱關係)
  • Lazy Class(冗贅類)

l  Responsibility(職責)

  • Feature Envy(依戀情節)
  • Message Chains(過分耦合的消息鏈)
  • Middle Man(中間轉手人)

l  Accommodating Change(協調變化)

  • Divergent Change(發散式變化)
  • Shotgun Surgery(霰彈式修改)
  • Parallel Inheritance Hierarchies(平行繼承體系)

l  Library Classes(庫類)

  • Incomplete Library Class(不完善的程序庫類)
  1. 代碼味道詳解

(1)    Long Method(過長函數)

l  描述:A method is too long.(方法太長。)

l  重構手段:

  • 把函數變小:Extract Method(提煉函數)
  • 函數內有大量的參數和臨時變量:Replace Temp with Query(以查詢取代臨時變量)
  • 參數太多:Introduce Parameter Object(引入參數對象)、Preserve Whole Object(保持對象完整)
  • 太多臨時變量和註釋:Replace Method with Method Object(以函數對象取代函數)
  • 條件表達式和循環:Decompose Conditional(分解條件表達式)

(2)    Large Class(過大類)

l  描述:A class is trying to do too much, it often shows up as too many instance variables.(一個類試圖作太多的事情,一般會出現太多的實例變量。)

l  重構手段:

  • 太多實例變量或太多代碼:Extract Class(提煉類)、Extract Subclass(提煉子類)
  • 肯定客戶端如何使用:Extract Interface(提煉接口)
  • 把數據和行爲移到一個獨立的領域對象,但須要保留一些重複數據:Duplicate Observed Data(複製「被監視數據」)

(3)    Long Parameter List(過長參數列)

l  描述:A method needs passing too many parameters.(一個方法須要傳遞太多的參數。)

l  重構手段:

  • 向已有對象發出一條請求就能夠取代一個參數:Replace Parameter with Method(以函數取代參數)
  • 參數缺少合理的對象歸屬:Introduce Parameter Object(引入參數對象)
  • 未來自同一個對象的一堆參數收集起來:Preserve Whole Object(保持對象完整)

(4)    Comments(過多的註釋)

l  描述:Do not write comments when it is unnecessary. When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.(在非必要的狀況下不要寫註釋。當你以爲須要去寫一段註釋時,你首先應該嘗試去重構代碼,這將使任何註釋都變得是多餘的。)

l  重構手段:

  • 須要註釋來解釋一塊代碼作了什麼:Extract Method(提煉函數)
  • 函數已經提煉出來,但仍是須要註釋來解釋其行爲:Rename Method(函數更名)
  • 須要註釋來講明某些系統的需求規格:Introduce Assertion(引入斷言)

(5)    Speculative Generality(誇誇其談的將來性)

l  描述:If a machinery was being used, it would be worth it. But if it is not, it is not. The machinery just gets in the way, so get rid of it.(若是一個裝置【一個設計或實現方案】會被用到,那就值得去作;若是用不到,就不值得。用不到的裝置會成爲攔路石,所以須要將它搬移。)

l  重構手段:

  • 某個抽象類沒有太大做用:Collapse Hierarchy(摺疊繼承體系)
  • 沒必要要的委託:Inline Class(將類內聯化)
  • 函數的某些參數未被使用:Remove Parameter(移除參數)
  • 函數名稱帶有多餘的抽象涵義:Rename Method(函數更名)
  • 對於無用的函數:Inline Method(內聯函數)、Remove Method(移除函數)

(6)    Duplicated Code(重複代碼)

l  描述:Same code structure happens in more than one place.(在一個以上的地方發現類似的代碼結構。)

l  類型:

  • 類型一:除空格、佈局和註釋不一樣以外,其他部分都相同的代碼片斷——採用字符串匹配檢測
  • 類型二:除標識符、字面量、類型、空格、佈局和註釋外,語法結構相同的代碼片斷——採用標準化檢測
  • 類型三:除標識符、字面量、類型、空格、佈局和註釋外,進一步對重複代碼段進行改動,例如修改、增長或者刪除語句——採用區域匹配檢測
  • 類型四:兩個或多個代碼片斷執行相同的計算(功能),可是語法結構的實現方式不一樣

l  重構手段:

  • 同一個類的一個/兩個方法含有相同的代碼: Extract Method(提煉函數)
  • 兩個互爲兄弟的子類含有相同的代碼:Extract Method(提煉函數)、Pull Up Method(函數上移)、Form Template Method(塑造模板函數)
  • 兩個絕不相關的類含有相同的代碼 :Extract Class(提煉類)

(7)    Alternative Classes with Different Interfaces(殊途同歸的類)

l  描述:Classes are doing similar things but with different signatures. (不一樣的類作相同的事情,卻擁有不一樣的簽名,主要是指方法簽名不一樣。)

l  重構手段:

  • 兩個函數作同一件事,卻有着不一樣的簽名:Rename Method(函數更名)
  • 將某些行爲移入類,直到二者的協議一致爲止:Move Method(搬移函數)
  • 必須重複而冗贅地移入代碼才能實現上述重構:Extract Superclass(提煉超類)

(8)    Switch StatementsSwitch驚悚現身)

l  描述:Switch statements often lead to duplication. Most times you see a switch statement which you should consider as polymorphism.(Switch語句一般會致使代碼重複。大多數時候,一看到Switch語句你應該考慮使用多態來替換。)

l  重構手段:

  • 與類型碼相關的函數或類:Extract Method(提煉函數)、Move Method(搬移函數)、Replace Conditional with Polymorphism(以多態取代條件表達式)、Replace Type Code with Subclass(以子類取代類型碼)、Replace Type Code with State/Strategy(以State/Strategy取代類型碼)
  • 只在單一函數中有一些選擇事件,且不想改動它們:Replace Parameter with Explicit Methods(以明確函數取代參數)
  • 選擇條件之一是null:Introduce Null Object(引入Null對象)

(9)    Primitive Obsession(基本類型偏執)

l  描述:Primitive types are overused in software. Small classes should be used in place of primitive types in some situations.(在軟件中,基本類型被過分使用。在某些場合下,應該使用一些小的類來代替這些基本類型。)

l  重構手段:

  • 將本來單獨存在的數據值替換成對象:Replace Data Value with Object(以對象取代數據值)
  • 若是想要替換的數據值是類型碼,而它並不影響行爲:Replace Type Code with Class(以類取代類型碼)
  • 若是有與類型碼相關的條件表達式: Replace Type Code with Subclass(以子類取代類型碼)、 Replace Type Code with State/Strategy(以State/Strategy取代類型碼)
  • 若是有一組應該老是被放在一塊兒的字段: Extract Class(提煉函數)
  • 若是在參數列中看到基本類型的數據: Introduce Parameter Object(引入參數對象)
  • 發現本身正從數組中挑選數據: Replace Array with Object(以對象取代數組)

(10) Data Class(純稚的數據類)

l  描述:These are classes that have fields, getting and setting methods for the fields, and nothing else. Such classes are dumb data holders and are almost certainly being manipulated in far too much detail by other classes.(這些類擁有一些字段【成員變量】,並提供了對應的Getter和Setter方法,除此之外一無全部。這些類只是一些不會說話的數據容器, 並且它們一定會被其餘類過度瑣細地操做。)

l  重構手段:

  • 對於public字段: Encapsulate Field(封裝字段)
  • 若是一個類內含容器類的字段,若是沒有獲得恰當的封裝: Encapsulate Collection(封裝集合)
  • 對於那些不應被其餘類修改的字段:Remove Setting Method(移除設值函數)
  • 找出Getter/Setter函數被其餘類運用的地點:Move Method(搬移函數)
  • 若是沒法搬移整個函數:Extract Method(提煉函數)
  • 將Getter/Setter函數隱藏起來:Hide Method(隱藏函數)

(11) Data Clumps(數據泥團)

l  描述:Some data items together in lots of places: fields in a couple of classes, parameters in many method signatures.(一些數據項同時出如今多個地方,例如一對類中的值域【成員變量】,多個方法簽名中的參數等。)

l  重構手段:

  • 兩個類中有相同的字段、許多函數簽名中的參數相同:Extract Class(提煉類)
  • 縮短參數列表、簡化函數調用:Introduce Parameter Object(引入參數對象)、Preserve Whole Object(保持對象完整)

(12) Temporary Field(使人迷惑的暫時值域)

l  描述:Sometimes you see an object in which an instance variable is set only in certain circumstances. Such code is difficult to understand, because you expect an object to need all of its variables.(有時候你會看到一個對象的實例變量僅爲某些特定的場合而設。這樣的代碼將致使難以理解,由於你指望一個對象須要它全部的變量。)

l  重構手段:

  • 一個對象中某個實例變量僅爲某種特定狀況而定:Move Field(搬移字段)
  • 在「變量不合法」的狀況下建立一個Null對象,從而避免寫出條件式代碼:Introduce Null Object(引入Null對象)

(13) Refused Bequest(被拒絕的遺贈)

l  描述:Subclasses get to inherit the methods and data of their parents, but they just use a few of them.(子類繼承父類的方法和數據,可是它們只須要使用其中的一部分。)

l  重構手段:

  • 子類不想或不須要繼承超類(先爲子類新建一個兄弟類):Extract Subclass(提煉子類)、Push Down Method(函數下移)、Push Down Field(字段下移)
  • 子類複用了超類的行爲(實現),卻又不肯意支持超類的接口,拒絕繼承超類的實現:Replace Inheritance with Delegation(以委託取代繼承)

(14) Inappropriate Intimacy(狎暱關係)

l  描述:Sometimes classes become far too intimate and spend too much time delving in each others’ private parts.(有時候,類之間的關係變得很是親密,而且須要花費大量時間來探究彼此之間的私有成分。)

l  重構手段:

  • 類之間的關係過於親密:Move Method(搬移函數)、Move Field(搬移字段)、Change Bidirectional Association to Unidirectional(將雙向關聯改成單向關聯)
  • 若是兩個類存在共同點:Extract Class(提煉類)、Hide Delegate(隱藏「委託關係」 )
  • 從繼承體系中分離子類:Replace Inheritance with Delegation(以委託取代繼承)

(15) Lazy Class(冗贅類)

l  描述:Each class you create costs money to maintain and understand. A class that is not doing enough to pay for itself should be eliminated.(你所建立的每一個類都須要花錢去維護和理解。一個類若是不值其身價,它就應該消失。)

l  重構手段:

  • 對於幾乎沒用的組件:Inline Class(將類內聯化)
  • 若是某些子類沒有作足夠的工做:Collapse Hierarchy(摺疊繼承體系)

(16) Feature Envy(依戀情節)

l  描述:The whole point of objects is that they are a technique to package data with the processes used on that data. A Feature Envy is a method that seems more interested in a class other than the one it actually is in.(對象的所有要點在於它是一種封裝數據以及施加於這些數據的處理過程的技術。依戀情節是指一個方法對別的類的興趣高過它自己所在的類。)

l  重構手段:

  • 函數對某個類的興趣高過對本身所處類的興趣:Move Method(搬移函數)、Move Field(搬移字段)
  • 函數中只有一部分對其餘類更感興趣:Extract Method(提煉函數)、Move Method(搬移函數)
  • 判斷哪一個類擁有最多被此函數使用的數據,而後就把這個函數和那些數據放在一塊兒

(17) Message Chains(過分耦合的消息鏈)

l  描述:You see message chains when a client asks one object for another object, which the client then asks for yet another object, which the client then asks for yet another object, and so on. Navigating in this way means that the client is coupled to the structure of the navigation. Any change to the intermediate relationships causes the client to have to change.(你看到的消息鏈是這樣的:當一個客戶端向一個對象請求另外一個對象,而後再向後者請求另外一個對象,而後再請求另外一個對象,如此反覆。這種方式的導航意味着客戶端將與整個導航結構緊密耦合在一塊兒。一旦對象之間的聯繫發生任何改變,將致使客戶端也不得不作出相應的修改。)

l  重構手段:

  • 存在一長串getThis()或一長串臨時變量:Hide Delegate(隱藏「委託關係」)

(18) Middle Man(中間轉手人)

l  描述:You look at a class’s interface and find that half the methods are delegating to this other class. It may mean problems.(當你審查一個類的接口時發現其中有一半的方法都委託給了其餘類,這也許就意味着存在問題了。)

l  重構手段:

  • 過分運用委託(一半及以上的函數都委託給其餘類):Remove Middle Man(移除中間人)
  • 若是「不幹實事」的函數只有少數幾個:Inline Method(內聯函數)
  • 若是中間人還有其餘行爲,須要對原對象的行爲進行擴展:Replace Delegation with Inheritance(以繼承取代委託)

(19) Divergent Change(發散式變化)

l  描述:Divergent change occurs when one class is commonly changed in different ways for different reasons.(若是某個類常常由於不一樣的緣由在不一樣的方向上發生變化就會產生髮散式變化。也就是說,一個類擁有多個引發它發生變化的緣由。)

l  重構手段:

  • 若是某個類常常由於不一樣的緣由在不一樣的方向上發生變化【找出某特定緣由而形成的全部變化】:Extract Class(提煉類)

(20) Shotgun Surgery(霰彈式修改)

l  描述:Shotgun surgery is similar to divergent change but is the opposite. Every time you make a kind of change, you have to make a lot of little changes to a lot of different classes.(霰彈式修改與發散式變化相似,卻又存在相反的一面。每次進行某種修改時,你都必須對多個不一樣的類進行不少對應的小修改。)

l  重構手段:

  • 把全部須要修改的代碼放進同一個類中:Move Method(搬移函數)、Move Field(搬移字段)
  • 若是眼下沒有合適的類能夠安置這些代碼,就創造一個
  • 把一系列相關行爲放進同一個類中:Inline Class(將類內聯化)

(21) Parallel Inheritance Hierarchies(平行繼承體系)

l  描述:Parallel inheritance hierarchies is really a special case of shotgun surgery. In this case, every time you make a subclass of one class, you also have to make a subclass of another. You can recognize this smell because the prefixes of the class names in one hierarchy are the same as the prefixes in another hierarchy.(平行繼承體系是霰彈式修改的一個特例。在這種狀況下,當你爲某個類增長一個子類時,你不得不爲另外一個類也相應增長一個子類。你也許可以識別到這種味道,由於一個繼承體系中類的類名前綴與另外一個體系中的類名前綴同樣。)

l  重構手段:

  • 讓一個繼承體系的實例引用另外一個繼承體系的實例:Move Method(搬移函數)、Move Field(搬移字段)

(22) Incomplete Library Class(不完善的程序庫類)

l  描述:Library classes should be used carefully, especially we do not know whether a library is completed.(庫類在使用時必定要當心,特別是在咱們不知道一個庫是否完整時。

l  重構手段:

  • 若是隻想修改庫類的一兩個函數:Introduce Foreign Method(引入外加函數)
  • 若是想要添加一大堆額外行爲:Introduce Local Extension(引入本地擴展)
  1. 經常使用重構技巧

(1)    從新組織函數(Composing Methods)

l  Extract Method(提煉函數)

  • 你有一段代碼能夠被組織在一塊兒並獨立出來。
  • 將這段代碼放進一個獨立函數中,並讓函數名稱解釋該函數的用途。

 

l  Inline Method(內聯函數)

  • 一個函數的本體與名稱一樣清楚易懂。
  • 在函數調用點插入函數本體,而後移除該函數。

 

l  Inline Temp(內聯臨時變量)

  • 你有一個臨時變量,只被一個簡單表達式賦值一次,而它妨礙了其餘重構手法。
  • 將全部對該變量的引用動做,替換爲對它賦值的那個表達式自身。

 

l  Replace Temp with Query(以查詢取代臨時變量)

  • 你的程序以一個臨時變量(temp)保存某一表達式的運算結果。
  • 將這個表達式提煉到一個獨立函數(即查詢式Query)中。將這個臨時變量的全部引用點替換爲對新函數的調用。此後,新函數就可被其餘函數所使用。

 

l  Introduce Explaining Variable(引入解釋性變量)

l  你有一個複雜的表達式。

l  將該複雜表達式(或其中一部分)的結果放進一個臨時變量,以此變量名稱來解釋表達式用途。

 

l  Split Temporary Variable(分解臨時變量)

  • 你的程序有某個臨時變量被賦值超過一次,它既不是循環變量,也不是用來收集計算結果的變量。
  • 針對每次賦值,創造一個獨立的、對應的臨時變量。

 

l  Remove Assignments to Parameters(移除對參數的賦值)

  • 你的代碼對一個參數進行賦值動做。
  • 以一個臨時變量取代該參數的位置。

 

l  Replace Method with Method Object(以函數對象取代函數)

  • 你有一個大型函數,其中對局部變量的使用使你沒法釆用 Extract Method。
  • 將這個函數放進一個單獨對象中,如此一來局部變量就成了對象內的字段。而後你能夠在同一個對象中將這個大型函數分解爲多個小型函數。

 

l  Substitute Algorithm(替換算法)

  • 你想要把某個算法替換爲另外一個更清晰的算法。
  • 將函數本體(method body)替換爲另外一個算法。

 

(2)    在對象之間搬移特性(Moving Features Between Objects)

l  Move Method(搬移函數)

  • 你的程序中,有個函數與其所駐類以外的另外一個類進行更多交流:調用後者,或被後者調用。【使用另外一個對象的次數比使用本身所駐對象的次數還多。】
  • 在該函數最常引用的類中創建一個有着相似行爲的新函數。將舊函數變成一個單純的委託函數(delegating method),或是將舊函數徹底移除。

 

l  Move Field(搬移字段)

  • 你的程序中,某個字段被其所駐類以外的另外一個類更多地用到。
  • 在目標類中新建一個字段,修改源字段的全部用戶,令它們改用此新字段。

 

l  Extract Class(提煉類)

  • 某個類作了應該由兩(多)個類作的事。
  • 創建一個新類,將相關的字段和函數從舊類搬移到新類

 

l  Inline Class(將類內聯化)

  • 某個類沒有作太多事情(沒有承擔足夠的責任)。
  • 將這個類的全部特性搬移到另外一個類中,而後移除原類。

 

l  Hide Delegate(隱藏「委託關係」)

  • 客戶經過一個委託類來調用另外一個對象。
  • 在服務類上創建客戶所需的全部函數,用以隱藏委託關係。

 

 

l  Remove Middle Man(移除中間人)

  • 某個類作了過多的簡單委託動做。
  • 讓客戶直接調用受託類。

 

 

l  Introduce Foreign Method(引入外加函數)

  • 你須要爲提供服務的類增長一個函數,但你沒法修改這個類。
  • 在客戶類中創建一個函數,並以第一參數形式傳入一個服務類實例。

 

l  Introduce Local Extension(引入本地擴展)

  • 你須要爲服務類提供一些額外函數,但你沒法修改這個類。
  • 創建一個新類,讓它包含這些額外函數。讓這個擴展品成爲源類的子類或包裝類【適配器模式或裝飾模式】。

 

(3)    從新組織數據(Organizing Data)

l  Self Encapsulate Field(自封裝字段)

  • 你直接訪問一個字段,但與字段之間的耦合關係逐漸變得笨拙。
  • 爲這個字段創建取值/設值(Getter/Setter)函數,而且只以這些函數來訪問字段。

 

l  Replace Data Value with Object(以對象取代數據值)

  • 你有一個數據項,須要與其餘數據和行爲一塊兒使用纔有意義。
  • 將數據項變成對象。

 

l  Change Value to Reference(將值對象改成引用對象)

  • 你從一個類衍生出許多彼此相等的實例,但願將它們替換爲同一個對象。
  • 將這個值對象變成一個引用對象。

 

l  Change Reference to Value(將引用對象改成值對象)

  • 你有一個引用對象,很小且不可變,並且不易管理。
  • 將它變成一個值對象。

 

l  Replace Array with Object(以對象取代數組)

  • 你有一個數組,其中的元素各自表明不一樣的東西。
  • 以對象替換數組。對於數組中的每一個元素,以一個字段來表示。

 

l  Duplicate Observed Data(複製「被監視數據」)

  • 你有一些領域數據置身於GUI控件中,而領域函數須要訪問這些數據。
  • 將這些數據複製到一個領域對象中。創建一個Observer模式,用以同步領域對象和GUI對象內的重複數據。

 

l  Change Unidirectional Association to Bidirectional(將單向關聯改成雙向關聯)

  • 兩個類都須要使用對方的特性,但其間只有一條單向鏈接。
  • 添加一個反向指針,並使修改雙方關係的函數可以同時更新兩條鏈接。

 

l  Change Bidirectional Association to Unidirectional(將雙向關聯改成單向關聯)

  • 兩個類之間有雙向關聯,但其中一個類現在再也不須要另外一個類的特性。
  • 去除沒必要要的關聯。

 

l  Replace Magic Number with Symbolic Constant(以字面常量取代魔法數)

  • 你有一個字面數值,帶有特別含義。
  • 創造一個常量,根據其意義爲它命名,並將上述的字面數值替換爲這個常量。

 

l  Encapsulate Field(封裝字段)

  • 你的類中存在一個public字段。
  • 將它聲明爲private,並提供相應的訪問函數。

 

l  Encapsulate Collection(封裝集合)

  • 有個函數返回一個集合。
  • 讓這個函數返回該集合的一個只讀副本,並在這個類中提供添加/移除集合元素的函數。

 

l  Replace Record with Data Class(以數據類取代記錄)

  • 你須要面對傳統編程環境中的記錄結構(Record Structure)。
  • 爲該記錄建立一個「啞」數據對象。

實例:將傳統的由JDBC返回的結果記錄,替換成一個簡單的值對象。

l  Replace Type Code with Class(以類取代類型碼)

  • 類之中有一個數值類型碼,但它並不影響類的行爲。
  • 以一個新的類替換該數值類型碼。

 

l  Replace Type Code with Subclasses(以子類取代類型碼)

  • 你有一個不可變的類型碼,它會影響類的行爲。
  • 以子類取代這個類型碼。

 

l  Replace Type Code with State/Strategy(以State/Strategy取代類型碼)

  • 你有一個類型碼,它會影響類的行爲,但你沒法經過繼承手法消除它。
  • 以狀態對象或者具體策略對象取代類型碼。

 

l  Replace Subclass with Fields(以字段取代子類)

  • 你的各個子類的惟一差異只在「返回常量數據」的函數身上。
  • 修改這些函數,使它們返回超類中的某個(新增)字段,而後銷燬子類。

 

(4)    簡化條件表達式(Simplifying Conditional Expressions)

l  Decompose Conditional(分解條件表達式)

  • 你有一個複雜的條件(if-then-else)語句。
  • 從if、then、else 三個段落中分別提煉出獨立函數。

 

l  Consolidate Conditional Expression(合併條件表達式)

  • 你有一系列條件測試,都獲得相同結果。
  • 將這些測試合併爲一個條件表達式,並將這個條件表達式提煉成爲一個獨立函數。

 

l  Consolidate Duplicate Conditional Fragments(合併重複的條件片斷)

  • 在條件表達式的每一個分支上有着相同的一段代碼。
  • 將這段重複代碼搬移到條件表達式以外。

 

l  Remove Control Flag(移除控制標記)

  • 在一系列布爾表達式中,某個變量帶有「控制標記」(control flag)的做用。
  • 以break語句或return的語句取代控制標記。

 

l  Replace Nested Conditional with Guard Clauses(以衛語句取代嵌套條件表達式)

  • 函數中的條件邏輯(Conditional Logic)令人難以看清正常的執行路徑。
  • 使用衛語句表現全部特殊狀況

 

l  Replace Conditional with Polymorphism(以多態取代條件表達式)

  • 你手上有個條件表達式,它能夠根據對象類型的不一樣而選擇不一樣的行爲。
  • 將這個條件表達式的每一個分支放進一個子類內的覆寫函數中,而後將原始函數聲明爲抽象函數。

 

l  Introduce Null Object(引入Null對象)

  • 你須要再三檢查某對象是否爲null。
  • 將null值替換爲null對象。

 

l  Introduce Assertion(引入斷言)

  • 某一段代碼須要對程序狀態作出某種假設。
  • 以斷言(assertion)明確表現這種假設。

 

(5)    簡化函數調用(Making Method Calls Simpler)

l  Rename Method(函數更名)

  • 函數的名稱未能揭示函數的用途。
  • 修改函數名稱。

 

l  Add Parameter(添加參數)

  • 某個函數須要從調用端獲得更多信息。
  • 爲此函數添加一個對象參數,讓該對象帶進函數所需信息。

 

l  Remove Parameter(移除參數)

  • 函數本體再也不須要某個參數。
  • 將該參數去除。

 

l  Separate Query from Modifier(將查詢函數和修改函數分離)

  • 某個函數既返回對象狀態值,又修改對象狀態。
  • 創建兩個不一樣的函數,其中一個負責査詢,另外一個負責修改。

 

l  Parameterize Method(令函數攜帶參數)

  • 若干函數作了相似的工做,但在函數本體中卻包含了不一樣的值。
  • 創建單一函數,以參數表達那些不一樣的值。

 

l  Replace Parameter with Explicit Methods(以明確函數取代參數)

  • 你有一個函數,其中徹底取決於參數值而採起不一樣行爲。
  • 針對該參數的每個可能值,創建一個獨立函數。

 

l  Preserve Whole Object(保持對象完整)

  • 你從某個對象中取出若干值,將它們做爲某一次函數調用時的參數。
  • 改成傳遞整個對象。

 

l  Replace Parameter with Method(以函數取代參數)

  • 對象調用某個函數,並將所得結果做爲參數,傳遞給另外一個函數。而接受該參數的函數自己也可以調用前一個函數。
  • 讓參數接受者去除該項參數,並直接調用前一個函數。

 

l  Introduce Parameter Object(引入參數對象)

  • 某些參數老是很天然地同時出現。
  • 以一個對象取代這些參數。

 

l  Remove Setting Method(移除設值函數)

  • 類中的某個字段應該在對象建立時被設值,而後就再也不改變。
  • 去掉該字段的全部設值函數。

 

l  Hide Method(隱藏函數)

  • 有一個函數,歷來沒有被其餘任何類用到。
  • 將這個函數修改成private。

 

l  Replace Constructor with Factory Method(以工廠函數取代構造函數)

  • 你但願在建立對象時不只僅是作簡單的建構動做。
  • 將構造函數替換爲工廠函數。

 

l  Encapsulate Downcast(封裝向下轉型)

  • 某個函數返回的對象,須要由函數調用者執行向下轉型(downcast)。
  • 將向下轉型動做移到函數中。

 

l  Replace Error Code with Exception(以異常取代錯誤碼)

  • 某個函數返回一個特定的代碼,用以表示某種錯誤狀況。
  • 改用異常。

 

l  Replace Exception with Test(以測試取代異常)

  • 面對一個調用者可預先檢查的條件,你拋出了一個異常。
  • 修改調用者,使它在調用函數以前先作檢查。

 

(6)    處理歸納關係(Dealing with Generalization)

l  Pull Up Field(字段上移)

  • 兩個子類擁有相同的字段。
  • 將該字段移至超類。

 

l  Pull Up Method(函數上移)

  • 有些函數,在各個子類中產生徹底相同的結果。
  • 將該函數移至超類。

 

l  Pull Up Constructor Body(構造函數本體上移)

  • 你在各個子類中擁有一些構造函數,它們的本體幾乎徹底一致。
  • 在超類中新建一個構造函數,並在子類構造函數中調用它。

 

l  Push Down Method(函數下移)

  • 超類中的某個函數只與部分(而非所有)子類有關。
  • 將這個函數移到相關的那些子類去。

 

l  Push Down Field(字段下移)

  • 超類中的某個字段只被部分(而非所有)子類用到。
  • 將這個字段移到須要它的那些子類中去。

 

l  Extract Subclass(提煉子類)

  • 類中的某些特性只被某些(而非所有)實例用到。
  • 新建一個子類,將上面所說的那一部分特性移到子類中。

 

l  Extract Superclass(提煉超類)

  • 兩個類有類似特性。
  • 爲這兩個類創建一個超類,將相同特性移至超類。

 

l  Extract Interface(提煉接口)

  • 若干客戶使用類接口中的同一子集,或者兩個類的接口有部分相同。
  • 將相同的子集提煉到一個獨立接口中。

 

l  Collapse Hierarchy(摺疊繼承體系)

  • 超類和子類之間無太大區別。
  • 將它們合爲一體。

 

l  Form Template Method(塑造模板函數)

  • 你有一些子類,其中相應的某些函數以相同順序執行相似的操做,但各個操做的細節上有所不一樣。
  • 將這些操做分別放進獨立函數中,並保持它們都有相同的簽名,因而原函數也就變得相同了。而後將原函數上移至超類。

 

l  Replace Inheritance with Delegation(以委託取代繼承)

  • 某個子類只使用超類接口中的一部分,或是根本不須要繼承而來的數據。
  • 在子類中新建一個字段用以保存超類;調整子類函數,令它改而委託超類;而後去掉二者之間的繼承關係。

 

l  Replace Delegation with Inheritance(以繼承取代委託)

  • 你在兩個類之間使用委託關係,並常常爲整個接口編寫許多極簡單的委託函數。
  • 讓委託類繼承受託類。

 

(7)    大型重構(Big Refactorings)

l  Tease Apart Inheritance(梳理並分解繼承體系)

  • 某個繼承體系同時承擔兩項責任。
  • 創建兩個繼承體系,並經過委託關係讓其中一個能夠調用另外一個。

 

l  Convert Procedural Design to Objects(將過程化設計轉化爲對象設計)

  • 你手上有一些以傳統的過程化風格編寫的代碼。
  • 將數據記錄變成對象,將大塊的行爲分紅小塊,並將行爲移入相關對象之中。

            

l  Separate Domain from Presentation(將領域和表述/顯示分離)

  • 某些GUI類之中包含了領域邏輯(Domain Logic)。
  • 將領域邏輯分離出來,爲它們創建獨立的領域類。

 

l  Extract Hierarchy     (提煉繼承體系)

  • 你有某個類作了太多工做,其中一部分工做是以大量條件表達式完成的。
  • 創建繼承體系,以一個子類表示一種特殊狀況。
相關文章
相關標籤/搜索