当前位置:编程学习 > asp >>

改善代码设计 —— 优化函数的构成(Composing Methods)

1. Extract Method (提炼函数)
解释:      如果发现一个函数的代码很长, 很可能的一种情况是这个函数做了很多事情, 找找看函数中有没有注释, 往往注释都是为了解释下面一块代码做的什么事情, 可以考虑将这块代码提炼(Extract)成一个独立的函数.

      这样做的好处不言而喻, 是面向对象五大基本原则中的单一职责原则 (Single Responsibility Principle), 比较长的函数被拆分成一个个小函数, 将有利于代码被复用.

冲动前:00 public void Print(Employee employee) 

01 { 

02     //print employees information 

03     Console.WriteLine("Name:" + employee.Name); 

04     Console.WriteLine("Sex:" + employee.Sex); 

05     Console.WriteLine("Age:" + employee.Age); 

06   

07     //print employees salary 

08     Console.WriteLine("Salary:" + employee.Salary); 

09     Console.WriteLine("Bonus:" + employee.Bonus); 

10 }
冲动后:00 public void Print(Employee employee) 

01 { 

02     //print employees information 

03     PrintInfo(employee); 

04   

05     //print employees salary 

06     PrintSalary(employee); 

07 } 

08   

09 public void PrintInfo(Employee employee) 

10 { 

11     Console.WriteLine("Name:" + employee.Name); 

12     Console.WriteLine("Sex:" + employee.Sex); 

13     Console.WriteLine("Age:" + employee.Age); 

14 } 

15 public void PrintSalary(Employee employee) 

16 { 

17     Console.WriteLine("Salary:" + employee.Salary); 

18     Console.WriteLine("Bonus:" + employee.Bonus); 

19 }

2. Inline Method (将函数内联)
解释:      有些函数很短, 只有一两行, 而且代码的意图也非常明显, 这时可以考虑将这个函数干掉, 直接使用函数中的代码.

      物件中过多的方法会让人感到不舒服, 干掉完全不必要的函数后代码会更简洁.

冲动前:0 public bool IsDeserving(int score) 

1 { 

2     return IsScoreMoreThanSixty(score); 

3 } 

4   

5 public bool IsScoreMoreThanSixty(int score) 

6 { 

7     return (score > 60); 

8 }
冲动后:0 public bool IsDeserving(int score) 

1 { 

2     return (score > 60) ; 

3 }

3. Inline Temp (将临时变量内联)
解释:      如果有一个临时变量 (Temp)用来表示某个函数的返回值, 一般来说, 这样的做法挺好的. 但如果这个临时变量实在多余, 将这个临时变量内联之后毫不影响代码的阅读, 甚至这个临时变量妨碍了其它重构工作, 就应该将这个临时变量内联化.

      把这个临时变量干掉的好处在于减少了函数的长度, 有时可以让其它重构工作更顺利的进行.

冲动前:0 int salary = employee.Salary; 

1 return (salary > 10000);
冲动后:0 return (employee.Salary > 10000);

4. Replace Temp With Query (用查询式代替临时变量)
解释:      程序中有一个临时变量(Temp)用来保存某个表达式的计算结果, 将这个计算表达式提炼(Extract)到一个独立的函数(即查询式Query)中, 将这个临时变量所有被调用的地方换成对新函数(Query)的调用, 新函数还可以被其它函数使用.

      好处在于减少函数长度, 增加代码复用率, 有利于代码进一步的重构. 并且注意 Replace Temp With Query 往往是 Extract Method 之前必不可少的步骤, 因为局部变量会使代码不太容易被提炼, 所以在进行类似的重构前可以将它们替换成查询式.

      下面的这个例子不是很有必要使用Replace Temp With Query, 主要展示如何 Replace Temp With Query. 试想"冲动前"函数中有很多个代码块都使用到 totalPrice, 突然有一天我发现这个函数太长, 我需要将这一块块的代码提炼成单独的函数, 这样就需要将 totalPrice = price * num; 放到每一个提炼出来的函数中. 而如果原来函数中使用的是查询式, 就不存在这个问题. 如果查询式中的计算量很大, 也不建议使用 Replace Temp With Query.

冲动前:0 public double FinalPrice(double price, int num) 

1 { 

2     double totalPrice = price * num; 

3     if (totalPrice > 100) 

4         return totalPrice * 0.8; 

5     else

6         return totalPrice * 0.9; 

7 }
冲动后:00 public double FinalPrice(double price, int num) 

01 { 

02     if (TotalPrice(price, num) > 100) 

03         return TotalPrice(price, num) * 0.8; 

04     else

05         return TotalPrice(price, num) * 0.9; 

06 } 

07 public double TotalPrice(double price, int num) 

08 { 

09     return price * num; 

10 }

5. Introduce Explaining Variable (引入可以理解的变量)
解释:      很多时候在条件逻辑表达式中, 很多条件令人难以理解它的意义, 为什么要满足这个条件? 不清楚. 可以使用Introduce Explaining Variable将每个条件子句提炼出来, 分别用一个恰当的临时变量名表示条件子句的意义.

      好处在于增加了程序的可读性.

冲动前:0 if((operateSystem.Contains("Windows"))&& 

1     (browser.Contatins("IE"))) 

2 { 

3     //do something 

4 }
冲动后:0 bool isWindowsOS = operateSystem.Contains("Windows"); 

1 bool isIEBrowser = browser.Contatins("IE"); 

2 if (isWindowsOS && isIEBrowser) 

3 { 

4     //do something 

5 }

6. Split Temporary Variable (撇清临时变量)
解释:      例如代码中有个临时变量在函数上面某处表示长方形周长, 在函数下面被赋予面积, 也就是这个临时变量被赋值超过一次, 且表示的不是同一种量. 应该针对每次赋值, 分配一个独立的临时变量.

      一个变量只应表示一种量, 否则会令代码阅读者感到迷惑.

冲动前:0 double temp = (width + height) * 2; 

1 //do something 

2 temp = width * height; 

3 //do something
冲动后:0 double perimeter = (width + height) * 2; 

1 //do something 

2 double area = width * height; 

3 //do something

7. Remove Assignments to Parameters (消除对参数的赋值操作)
解释:      传入参数分"传值"和"传址"两种, 如果是"传址", 在函数中改变参数的值无可厚非, 因为我们就是想改变原来的值. 但如果是"传值", 在代码中为参数赋值, 就会令人产生疑惑. 所以在函数中应该用一个临时变量代替这个参数, 然后对这个临时变量进行其它赋值操作.

冲动前:0 public double FinalPrice(double price, int num) 

1 { 

2     price = price * num; 

3     //other calculation with price 

4     return price; 

5 }
冲动后:0 public double FinalPrice(double price, int num) 

1 { 

2     double finalPrice = price * num; 

3     //other calcu

补充:Web开发 , ASP.Net ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,