11 java refactoring
现在推荐使用Query Temp with Query重构方法进行相当广泛的推广,但似乎非常低效,只获得很少的收益.
Martin Fowler网站的方法给出了以下示例:
将表达式提取到方法中.用表达式替换对temp的所有引用.然后可以在其他方法中使用新方法.
double basePrice = _quantity * _itemPrice;
if (basePrice > 1000)
return basePrice * 0.95;
else
return basePrice * 0.98;
Run Code Online (Sandbox Code Playgroud)
变
if (basePrice() > 1000)
return basePrice() * 0.95;
else
return basePrice() * 0.98;
double basePrice() {
return _quantity * _itemPrice;
}
Run Code Online (Sandbox Code Playgroud)
为什么这是个好主意?这肯定意味着计算不必要地重复,你有调用函数的开销.我知道CPU周期很便宜,但这样扔掉它们似乎不小心?
我错过了什么吗?
我现在正在重新阅读 Refactoring,原因之一是Extract Method
p.116末尾的以下引用。
背景:他描述了Extract Method
如果提取的代码使用局部变量很难。
临时变量通常非常丰富,以至于它们使提取变得非常困难。在这些情况下,我尝试通过使用 Replace Temp with Query (120) 来降低温度。...
因此,一次重构可能取决于首先进行另一次本身并不明显的重构。另一个例子是Inline Method
在 Replace 之前Method with Method Object
。
阅读过Fowler的网页后,我认为这样做没有任何好处.唯一可能的收获是通过将可能经常使用的表达式隔离到一个点,但最好通过以下方式处理:
double basePrice = basePrice();
if (basePrice > 1000)
return basePrice * 0.95;
else
return basePrice * 0.98;
Run Code Online (Sandbox Code Playgroud)
除了阅读他的书之外,福勒没有解释为什么他修改后的代码比原版更好.
您(最初的提问者和詹姆斯·柯兰)错过了在这个特定的例子中,计算没有重复。代码要么进入 的一个分支if
,然后调用basePrice()
来执行计算。或者代码进入另一个分支if
并在那里执行计算。
不管怎样,乘法都会进行,但仍然只进行一次。就像临时版本一样。
\n是的,最好知道查询默认情况下不被缓存,并且临时本质上是缓存的一种形式。在这个特定的例子中,这种区别并不重要。缓存(例如临时)的优点是它可以提供CPU周期节省(在这种情况下并非如此,就乘法本身而言,我的意思是\ xe2 \ x80 \ x94在调用,堆栈跳转等方面,那么当然\xe2\x80\xa6 取决于编译器)。缓存的缺点是,如果您不小心,它可能会提供过时或错误的数据。除此之外,福勒还提到了临时变量的具体缺点(它们在时间上和词汇上都是本地的)。
\n我通常做的是,我大部分时间都在查询中编写代码,当我看到我确实多次调用特定查询时(与此示例不同,它位于单独的条件分支中),我可以使用临时值(如果它是本地的)或引入的临时值如果我需要在更广泛、更少局部的范围内访问它,则可以使用记忆化或其他类型的缓存系统(例如简单的全局变量或类成员)。
\n这时,与此重构相反的“用 Temp 替换查询”就派上用场了。
\n我认为这种重构的大部分效用不是来自于它本身的应用,而是作为迈向极其常见和有用的提取方法的一步。在局部变量妨碍 Extract Method 或通过附加参数使其复杂化的情况下,“用查询替换 temp 帮助”使提取方法更容易。同样在这些情况下,生成的查询方法会被两种不同的方法重用,这些方法是提取方法的结果。
小智 5
在 Refactoring book 中还有更多关于 Replace Temp with Query 的内容,它是:
在这种情况下,您可能会担心性能。与其他性能问题一样,暂时让它滑动。十有八九,没关系。当它确实重要时,您将在优化期间解决问题。随着您的代码更好地分解,您通常会发现更强大的优化,如果不重构,您就会错过这些优化。如果情况变得更糟,很容易恢复温度。
小智 5
这是重要的重构,因为它是对单一职责的重构,它是DRY失败的解决方案!
临时文件的主要问题(特别是在使用长方法的幼稚代码中,长数百行!)是临时变量,它们是局部状态。明显的风险(如Fowler所讨论的那样)是,某人可能会在很长的方法中途进行更改,并最终破坏某些内容。(已看到产生的费用)
没有测试,此方法具有多种依赖性-真是一团糟!:)
删除临时人员是关于重构为单一职责。
示例-今天我发现了一个错误,它与将错误的temp变量传递到服务有关。如果我删除临时文件(有多个字符串),就不会发生该错误(疏忽)。
我的方法持有一个temp变量的原因是它在做它不应该做的工作...并且类似的类重复了此逻辑...是否全部一致?没有!
通过删除temp,我还将代码重构为具有适当职责的类,通过一些简单的测试即可覆盖110%。
没有巨大的工具可以测试琐碎的事情
如果我调用一些昂贵的东西,我将把结果作为值对象/集合返回。“临时代码”可能应该由集合内部化。
因此,删除temp将使您承担集中(单一)的职责-> SOLID!
其目的是更能揭示代码的意图。在某些情况下,它可能会被滥用,但可能性不大。例如,您可以使用查询来更新 5% 和 2% 折扣的查询,但使用您可以在折扣名称原因中描述的方法名称。请记住,今天可能很明显,但 6 个月后可能就不是这样了 - 正如我所说 - 问题不在于我是否忘记,而在于我什么时候忘记。
if (basePrice() > 1000)
return bigTicketDiscount()
else
return regularDiscount()
double bigTicketDiscount(){
return basePrice() * 0.95;
}
double regularDiscount(){
return basePrice() * 0.98
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2409 次 |
最近记录: |