1、Duplicate Code(重復代碼):代碼重復幾乎是最常見的異味了,他也是Refactoring的主要目標之一,代碼重復往往來自於copy-and-paste編程風格,與他相對應的OAOO是一個好系統的重要標志。
2、 Long Method(長方法):他是傳統結構化的遺毒,一個方法應該具有自我獨立的意圖,不要把幾個意圖放在一起。
3、 Large Class(大類):不要把太多的責任交給一個類。
4、Divergent Change(發散式變化):類中的各部分內容變化頻率相差很大,有些狀態一小時變化一次,有些則幾個月甚至幾年變化一次,導致各內容狀態發生變化的原因也不同。面向對象的抽象就是把相對不變的和相對變化的相隔離,把問題變化的一方面和另一方面相隔離,這可以使相對不變的可以重用,問題變化的每個方面都可以單獨重用。
5、 Shotgun Surgery(散彈式修改):和以上相反,對系統一個地方的改變涉及到其他許多地方的相關改變,這些變化率和變化內容相似的狀態和行為通常應該放在同一個類中。
6、 Feature Envy(特性依賴):對象的目的就是封裝狀態以及與這些狀態緊密相關的行為。假如一個類的方法頻繁用get 方法存取其他類的狀態進行計算,那么你要考慮把行為移到涉及狀態數目最多的那個類。
7、Data Clumps(數據堆積):某些數據一起出現在很多類的成員變量中,一起出現在許多方法的參數中。這些數據可以獨立形成對象。
8、Primitive Obsession(一味的使用原始數據類型):面向對象的新手習慣於用原始類型的數據來表示一個概念,比如對於范圍會用兩個數字,對於money會有浮點,因為新手沒有使用對象來表達問題中存在的概念,這使得代碼難以理解,解決問題的難度增大。好的習慣是擴充語言所提供的原始數據類型,用小對象來表示范圍、money、轉化率、郵政編碼等數據對象。
9、Switch Statement(常量開關):基於常量的開關是OO的大敵,應該用子類、State或者Strategy。
10、Parallel Inheritance Hierarchies(並行的繼承層次):並行的繼承層次是Shotgun Surgery的極端情況,因為改變一個層次中某個類時必須同時改變另一個層次中的並行子類。
11、Lazy Class(懶惰的類):一個功能很少的類,類的維護需要額外的開銷,如果一個類承擔了太少的責任,那么應該消除。
12、Speculative Generality(理論上的通用):一個類如果實現了從未用到的功能和通用性,通常這樣的類或方法的唯一用戶就是testcase,刪除。
13、Temporary Field(孤兒屬性):一個對象的屬性只能在某些特定的情況下才有意義。這樣的代碼將難以理解,專門建立一個對象來持有這些孤兒屬性,把只和他相關的行為移到該類。最常用的就是一個特定的算法需要某些只有該算法才有用的變量。
14、Message Chain(消息鏈):消息鏈發生於當一個客戶向一個對象要求另一個對象,然后客戶又向另一個對象要求另一個對象,再向這另一個對象要求另外的對象,如此。這種情況需要隱藏分派。
15、Middle Main(中間人):面向對象的基本特性之一就是封裝,而你經常會通過分派去實現封裝,但是這一步不能走太遠,假如你發現一個類接口的一大半方法都在做分派,那么你可能就需要移去這個中間人。
16、Inappropriate Intimacy(過度的親密):某些類相互之間過於親密,他們用了太多的時間去研究對方的私有部分。
17、Alternative Classes with Different Interfaces(不同接口中的可相互替代的類或方法):做相同的事情的方法有不同的函數signature,一致把它們往類層次上移動,直至協議一致。
18、Incomplete Library Class(不完整的類庫):要建立一個好的類庫很困難,我們大量的程序工作都是基於類庫實現。然而,如此廣泛而相異的目標對類庫構建者提出了苛刻的要求,類庫構建者也不是萬能的,有時候我們會發現庫類無法實現我們的功能,而直接對類庫的修改又十分困難,這時就需要用各種方法進行Refactoring(重構)。
19、 Data Class(數據類):數據對象包括狀態和行為,如果一個數據對象只有狀態而沒有行為,那么肯定是什么地方出問題了。