1. Extract Method (提炼函数)

解释:

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

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

冲动前:

public void Print(Employee employee)
{//print employee's informationConsole.WriteLine("Name:" + employee.Name);Console.WriteLine("Sex:" + employee.Sex);Console.WriteLine("Age:" + employee.Age);//print employee's salaryConsole.WriteLine("Salary:" + employee.Salary);Console.WriteLine("Bonus:" + employee.Bonus);
}

冲动后:

public void Print(Employee employee)
{//print employee's informationPrintInfo(employee);//print employee's salaryPrintSalary(employee);
}public void PrintInfo(Employee employee)
{Console.WriteLine("Name:" + employee.Name);Console.WriteLine("Sex:" + employee.Sex);Console.WriteLine("Age:" + employee.Age);
}
public void PrintSalary(Employee employee)
{Console.WriteLine("Salary:" + employee.Salary);Console.WriteLine("Bonus:" + employee.Bonus);
}

2. Inline Method (将函数内联)

解释:

有些函数很短, 只有一两行, 而且代码的意图也非常明显, 这时可以考虑将这个函数干掉, 直接使用函数中的代码.

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

冲动前:

public bool IsDeserving(int score)
{return IsScoreMoreThanSixty(score);
}public bool IsScoreMoreThanSixty(int score)
{return (score > 60);
}

冲动后:

public bool IsDeserving(int score)
{return (score > 60) ;
}

3. Inline Temp (将临时变量内联)

解释:

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

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

冲动前:

int salary = employee.Salary;
return (salary > 10000);

冲动后:

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.

冲动前:

public double FinalPrice(double price, int num)
{double totalPrice = price * num;if (totalPrice > 100)return totalPrice * 0.8;elsereturn totalPrice * 0.9;
}

冲动后:

public double FinalPrice(double price, int num)
{if (TotalPrice(price, num) > 100)return TotalPrice(price, num) * 0.8;elsereturn TotalPrice(price, num) * 0.9;
}
public double TotalPrice(double price, int num)
{return price * num;
}

5. Introduce Explaining Variable (引入可以理解的变量)

解释:

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

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

冲动前:

if((operateSystem.Contains("Windows"))&&(browser.Contatins("IE")))
{//do something
}

冲动后:

bool isWindowsOS = operateSystem.Contains("Windows");
bool isIEBrowser = browser.Contatins("IE");
if (isWindowsOS && isIEBrowser)
{//do something
}

6. Split Temporary Variable (撇清临时变量)

解释:

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

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

冲动前:

double temp = (width + height) * 2;
//do something
temp = width * height;
//do something

冲动后:

double perimeter = (width + height) * 2;
//do something
double area = width * height;
//do something

7. Remove Assignments to Parameters (消除对参数的赋值操作)

解释:

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

冲动前:

public double FinalPrice(double price, int num)
{price = price * num;//other calculation with pricereturn price;
}

冲动后:

public double FinalPrice(double price, int num)
{double finalPrice = price * num;//other calculation with finalPricereturn finalPrice;
}

8. Replace Method with Method Object (用函数物件代替函数)

解释:

冲动的写下一行行代码后, 突然发现这个函数变得非常大, 而且由于这个函数包含了很多局部变量, 使得无法使用 Extract Method, 这时 Replace Method with Method Object 就起到了杀手锏的效果. 做法是将这个函数放入一个单独的物件中, 函数中的临时变量就变成了这个物件里的值域 (field).

冲动前:

class Bill
{public double FinalPrice(){double primaryPrice;double secondaryPrice;double teriaryPrice;//long computation...}
}

冲动后:

class Bill
{public double FinalPrice(){return new PriceCalculator(this).compute();}
}
class PriceCalculator
{double primaryPrice;double secondaryPrice;double teriaryPrice;public PriceCalculator(Bill bill){//initial}public double compute(){//computation}
}

9. Substitute Algorithm (替换算法)

解释:

有这么一个笑话:

某跨国日化公司, 肥皂生产线存在包装时可能漏包肥皂的问题, 肯定不能把空的肥皂盒卖给顾客, 于是该公司总裁命令组成了以博士牵头的专家组对这个问题进行攻关, 该研发团队使用了世界上最高精尖的技术 (如红外探测, 激光照射等), 在花费了大量美金和半年的时间后终于完成了肥皂盒检测系统, 探测到空的肥皂盒以后, 机械手会将空盒推出去. 这一办法将肥皂盒空填率有效降低至5%以内, 问题基本解决.

而某乡镇肥皂企业也遇到类似问题, 老板命令初中毕业的流水线工头想办法解决之, 经过半天的思考, 该工头拿了一台电扇到生产线的末端对着传送带猛吹, 那些没有装填肥皂的肥皂盒由于重量轻就都被风吹下去了...

这个笑话可以很好的解释 Substitute Algorithm, 对于函数中复杂的算法, 尽量想办法将这个算法简单化, 从而达到与之前同样甚至更好的效果.

本文链接: http://www.cnblogs.com/technology/archive/2011/05/10/2042255.html

转载于:https://www.cnblogs.com/technology/archive/2011/05/10/2042255.html

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

  1. 改善代码设计 —— 组织好你的数“.NET研究”据(Composing Data)

    系列博客 1. 改善代码设计 -- 优化函数的构成(Composing Methods) 2. 改善代码设计 -- 优化物件之间的特性(Moving Features Between Objects) ...

  2. 改善代码设计 —— 简化条件表达式(Simplifying Conditional Expressions)

    系列博客 1. 改善代码设计 -- 优化函数的构成(Composing Methods) 2. 改善代码设计 -- 优化物件之间的特性(Moving Features Between Objects) ...

  3. 改善代码设计 —— 总结篇(Summary)

    系列博客 1. 改善代码设计 -- 优化函数的构成(Composing Methods) 2. 改善代码设计 -- 优化物件之间的特性(Moving Features Between Objects) ...

  4. 改善代码设计 —— 处理概括关系(Dealing with Generalization)

    1. Pull Up Field (提升值域) 解释: 如果发现每个子类都拥有相同的某个值域, 那么使用 Pull Up Field 将这个值域提升到父类中去. 冲动前: 冲动后: 2. Pull U ...

  5. 改善代码设计 —— 优化物件之间的特性(Moving Features Between Objects)

    1. Move Method (函数搬家) 解释: 如果 ClassA 的某个函数对 ClassB 有过多的依赖, 可以考虑将这个函数搬到 ClassB 中, 在 ClassA 的这个函数中直接调用 ...

  6. 《重构-改善既有代码设计》读书笔记-重构篇

    2019独角兽企业重金招聘Python工程师标准>>> 重构定义 名词 对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本.--<重 ...

  7. 重构-改善既有的代码设计-------代码的坏味道

    重构-改善既有的代码设计 代码的坏味道 神秘命名(Mysterious Name) 给函数.变量.模块和类命名时,要使它能清晰地表明自己的功能和用法,使得写下的代码直观明了. 常用重构手法为重命名,包 ...

  8. 重构改善既有代码设计

    目录 一.什么是重构 二.重构的目的和时机 2.1 目的 2.1.1 改进软件的设计 2.2.2 使软件更容易理解 2.2.3 帮助找到 BUG 2.2.4 提高编程速度 2.2 重构的时机 2.3 ...

  9. 重构与模式:改善代码三部曲中的第三部

    一.改善代码的三部曲 <设计模式>-> <重构>-> <重构与模式>.也就是设计->重构->重构出新设计. <设计模式>主要详细 ...

最新文章

  1. Mongodb aggregation 基本操作示例
  2. 信号编程之sigaction函数和sigqueue函数
  3. send/recv阻塞和非租塞不同
  4. 《研磨设计模式》chap3 外观模式Facade
  5. 想学python怎么学习_新手如何自学python课程?
  6. 【若依(ruoyi)】No message found under code ‘xxx‘ for locale ‘zh_CN‘.
  7. Windows—JDK安装与环境变量配置
  8. mysql数据备份在哪里_mysql之数据备份与恢复
  9. python webdriver脚本例子_Selenium webdriver添加cookie实现过程详解
  10. 【kafka】kafka 消费报错 Failed to add leader for partitions
  11. 【Nodejs】npm cnpm 淘宝镜像
  12. 标准c语言有几个关键字,C语言有多少个关键字
  13. 圣诞节PPT模板制作技巧分析
  14. 【鱼眼镜头2】[鱼眼畸变模型]:评估了五个模型:radial,division,FOV,多项式(如双三次]和rational模型。
  15. 线性代数 前五章知识点梳理总结
  16. QT 操作 QLabel
  17. 【Python】8.有益的探索
  18. 成为测试大牛——测试领域的变与不变
  19. .dll处位于.exe中引发的异常:0xC0000005:读取位置XXX时发生访问冲突
  20. fh admin mysql版本_在用mysql-front的时候遇到显示:程序注册时间到期程序将被限制模式下运行。...

热门文章

  1. 智能工厂在智能制造企业中的实践应用-东杰智能
  2. 九阴真经服务器维护,《九阴真经》-官方网站-一亿人的真武侠梦,开创全自由空中打斗...
  3. java加载tensorflow训练的PB模型记录
  4. 东北林业大学OJ题目2
  5. 痞子衡嵌入式:利用GPIO模块来测量i.MXRT1xxx的系统中断延迟时间
  6. 免费回收站恢复软件有哪些?数据恢复软件,这三款就足够了
  7. 使用jersey框架上传图片到图片服务器
  8. Ubuntu Kylin V10安装python3.10.4
  9. NIOS 外存 SDRAM(华邦 W9864G6KH)
  10. NIOS II 8:SDRAM(W9825G6KH-6),从这里开始使用软件版本改为18.