Move Method

  • 2114
  • 0
  • C#
  • 2009-12-29

想必有很多工程師跟小弟一樣會碰到要幫別人維護code的差事

在維護別人的code時難免會發現

想必有很多工程師跟小弟一樣會碰到要幫別人維護code的差事

在維護別人的code時難免會發現

  1. 前人因為某些因素導致code寫的不夠完善需要調整
  2. 或是系統需求有變動
  3. 也或許是有更好的做法而必須改程式

通常系統沒有錯誤當然是能不改就不改

但是當系統有錯誤或開發尚未完成等

其實是有技巧用來改善原本的程式的

什麼技巧?

不就是經驗嗎~

經驗老到的工程師往往可以用很快的速度將程式翻新、改善的

不過其實還有另外一門學問叫做重構

 

重構的理由非常多

大多數的理由是為了接下來的開發能夠更順利(廢話)

好比將過度肥大的Method切割

將奇怪命名的Method等重新調整為語意清楚的命名方式(好比小弟就曾看過有工程師喜歡用xx、oo、GetEmlByDept1、GetEmpByDept2等的命名方式)

讓類別責任清楚

讓程式容易理解等等~

 

最近小弟因為手頭的程式實在不小

原本不想變動的(基於成是看起來似乎沒有錯誤)

但是實在是越看越不對勁(一個類別有上千行程式,且部分程式很明顯應該是屬於另外的Class Family(註 1)的)

所以我就忍痛邊測試邊重構了

基本上我只用了move method跟extract method

 

開始吧(底下的程式只擷取部分的故僅僅做為sample用,並不多考慮實務上設計)

首先我的專案中有兩種種類的類別

第一種是類似Table Class的類別我將它放在 XXX.Model的命名空間下

命外一種是用來取得資料的類別,我將它放在XXX.DAL的命名空間下

今天我發現在DAL.Employee中包含了過多的關於Department的資訊

所以我決定把Employee的Method移回Department


class Employee
{
    string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
    public List<string> GetEmployeeName()
    {
        Department _dept = new Department();
        List<string> _result = new List<string>();
        List<Employee> _employeeList = _dept.GetEmployee("IT");
        foreach (Employee item in _employeeList)
        {
            _result.Add(item.Name);
        }
        return _result;
    }
}

class Department
{
    public List<Employee> GetEmployee(string departmanetName)
    {
        List<Employee> _result;
        DbProviderFactory dbHelp = DbProviderFactories.GetFactory("System.Data.SQLite");
        DbConnection _conn = dbHelp.CreateConnection();
        DbCommand _cmd = ....
        return _result;
    }

    ...
    ....
}

假設原本的Code是這樣的

我想GetEmployeeName放在Department會比放在employee更適合吧

所以我打算 move method

image

在我Move他之前我先確定了一下目前系統中有多少地方參照到要被我搬移的Method

如果我發現參照到次method的地方沒超過3個我想我會直接把整個GetEmployeeName移到Department中即可

並在做完move method後到每個有參照到的地方改寫原本的


Employee _emp = new Employee();
_emp.GetEmployeeName("IT");

為以下


Department _dept = new Department();
_dept.GetEmployeeName("IT");

如果我發現目前系統已經有太多地方參照它了

那麼我會改為使用工具協助(會比人工輕鬆一點)

我使用CodeRushXpress來協助我的作業

我只要將要被搬移的程式反白按下Ctrl + `就會出現此畫面

image

選完Extract method to Department按下Enter後

image

然後我改變return Department.GetEmployeeNameExtracted(departmentName);的method name為GetEmployeeName

我只要改變return中的method name在department中的method name也會變動

image

接下來我需要將 department中GetEmployeeName的static拿掉並在emplayee中的GetEmployeeName改為要instance department並調整

在department中的GetEmployeeName不需要再instance department囉

image

最後我的code會長成這樣

目前就先這樣吧,

先讓類別做自己該做的事

不要做不相關的事

這樣也可以消除掉employee對department過度的相依性

 

另外您也可以考慮使用ObsoleteAttribute套用在被取代掉的Method

例如


[Obsolete("此Method已經過期,請改用XXX")]
public List<string> GetEmployeeName()
    {

這樣以後維護的人員在compiler時就會注意到此method要改用新類別中的method了

 

Refactoring

ObsoleteAttribute 類別 

 

註 1:這是參考深入淺出設計模式中的演算法家族說法,相同性質功能的類別歸類為同一個家族,因為我想不到更好的說法,抱歉。