1. 程式人生 > >程式碼重構實踐:去除重複程式碼、提高可擴充套件性

程式碼重構實踐:去除重複程式碼、提高可擴充套件性

        最近,公司領導突然想起來要看每日業務量統計報告,還好之前一位同事寫過一個python指令碼,通過掃描系統日誌檔案分類統計不同業務的數量,整個指令碼有如下兩個配置資訊:

  • 命令中文名稱配置檔案: 

       cmd_cfg = { "cmd_A_1" :"業務A_1", 

                           "cmd_A_2" :"業務A_2",

                           ... ...

                           "cmd_B_1" :"業務B_1", 

                           "cmd_B_2" :"業務B_2",

                           ... ...

                         }

  • 命令陣列:

        cmd_A = ["cmd_A_1",  "cmd_A_2",  ...]

        cmd_B = ["cmd_B_1",  "cmd_B_2",  ...]

        整個指令碼的邏輯是在日誌檔案中逐個命令陣列搜尋每個命令組中的命令,統計每個命令出現的次數及在整個命令組中的佔比量,最後,以中文名稱輸出上述每組命令的統計值及命令組的名稱。

for cmd in cmd_A:

    #count cmd in log

    #print cmd_cfg[cmd], count

    #sum of count

print cmd_A sum

for cmd in cmd_B:

    #count cmd in log

    #print cmd_cfg[cmd], count

    #sum of count

print cmd_B sum

… …

        上面的程式碼一眼看去,就會看到大量明顯重複的程式碼,其主要差別無非最後輸出的命令組的名稱不同而已。此外,一個更重要的問題是每個命令的中文名稱配置在一個獨立的字典結構裡面,這樣每當有新的命令加進來的時候,中文名稱配置檔案和命令陣列就需要同步修改,給整個指令碼的可擴充套件性帶來很大的不方便。

        首先的重構,是把原來的‘cmd_cfg’中的中文名稱對映,分散到每個命令陣列中,把命令陣列變更為命令字典,這樣對於原來命令陣列的遍歷,無非變為對每個命令字典的keys的遍歷。這樣,就不再需要單獨的命令中文名稱配置檔案,以後有新的命令加入時,只需要按照業務分類加入相應的命令字典即可。

  • 命令字典:

cmd_A = {  "cmd_A_1":"業務A_1", 

                  "cmd_A_2":"業務A_2",

                  ... ...

               }

cmd_B = { "cmd_B_1":"業務B_1",

                 "cmd_B_2":"業務B_2",

                 ...

               }

for cmd, name in cmd_A.items():

    #count cmd in log

    #print name, count

    #sum of count

print cmd_A sum

for cmd, name in cmd_B.items():

    #count cmd in log

    #print name, count

    #sum of count

print cmd_B sum

… …

        第一步的重構,解決了命令中文名稱配置分散的問題,但仍有大量的重複的幾乎完全一樣的for迴圈存在。前面已經說過,每個for迴圈的差異無非最後要輸出的命令組的名字,我想到的一個辦法是把這個名字也放到各個命令字典裡面去,給這個名字設定一個特殊的key值,最後在需要輸出命令組名字的時候,用這個特殊的key到相應的命令字典獲取即可。

cmd_A = { "group_name":"cmd_A",

                 "cmd_A_1":"業務A_1", 

                 "cmd_A_2":"業務A_2",

                 ... ...

               }

cmd_B = { "group_name":"cmd_B",

                 "cmd_B_1":"業務B_1",

                 "cmd_B_2":"業務B_2",

                 ... ...

               }

for cmd, name in cmd_A.items():

    #count cmd in log

    #print name, count

    #sum of count

print cmd_A[“group_name”] sum

for cmd, name in cmd_B.items():

    #count cmd in log

    #print name, count

    #sum of count

print cmd_B[“group_name”] sum

… …

         從上面的程式碼可以看出,不僅每個for迴圈的結構完全一樣,最後輸出名字組名字的操作也是一樣的,因而,可以進一步優化,把所有的命令字典組成一個大的陣列,用一個外層的for迴圈遍歷這個大陣列,內部的一層for迴圈則與原來的for迴圈邏輯一樣。

groups = [cmd_A, cmd_B, ……]

for grp in groups:

    for cmd, name in cmd_A.items():

        #count cmd in log

        #print name, count

        #sum of count

    print grp[“group_name”] sum

… …

        最後,經過上述三步重構,不僅廢棄了冗餘的命令中文名稱配置檔案,還將原來的十幾個幾乎完全一樣的for迴圈,簡化為一個for迴圈。這樣,不僅程式碼更精煉,為後續的命令擴充套件也提供了很大的便利:某個命令組新增命令只需要修改相應的命令字典;新增命令組時,則只需要擴充套件‘groups’陣列即可。