相信大家多多少少都有遇過,看到某一段類似下面的代碼。
看上去HasEvenNumber會判斷numbers中是否存在。
if (!HasEvenNumber(numbers))
{
return 0;
}
return _evenNumbers.Sum();
但是如果移進HasEvenNumber一看可以發現
private bool HasEvenNumber(List<int> numbers)
{
bool hasEvenNumber = false;
foreach (var number in numbers)
{
if (number % 2 == 0)
{
hasEvenNumber = true;
_evenNumbers.Add(number);
}
}
return hasEvenNumber;
}
HasEvenNumber這個方法做了兩件事情
假設其他團隊成員讀到這段代碼,當他看到HasEvenNumber這個名稱,通常會預期這個方法會判斷是否numbers中包含偶數,而不會預期還會把偶數加到_evenNumbers。
如果他在其他地方也需要判斷偶數,他拿著這個方法到處使用,卻發現怎麼程式錯了,除錯除了半天發現_evenNumbers怎麼出現一大堆重複的偶數,在追到原來是HasEvenNumber在搞鬼,此時他的眼白已經佔據了整個眼眶。
所以在抽取方法時,讓方法名稱描述方法的行為是非常重要的事情。以HasEvenNumber為例,可以發現如果想把方法命名精準,會變成HasAndUpdateEvenNumber、HasEvenNumberAndUpdate...之類。
可以發現上面的名字都很長,而且十分難以命名。此時應該就要意識到這個方法做了太多事情了,我們應該要把他拆開,讓他們的功能單一。
private void UpdateEvenNumber(List<int> numbers)
{
foreach (var number in numbers)
{
if (number % 2 == 0)
{
_evenNumbers.Add(number);
}
}
}
private bool HasEvenNumber(List<int> numbers)
{
return _evenNumbers.Any(number => true);
}
不論變數名稱或方法名稱,命名時都盡量讓名稱能正確表達他們的內容。維持這個原則之後,當發現名稱非常不好命名時,就會發現這個變數儲存了不同意義的東西或方法做了太多事情,此時就應該思考應該要怎麼調整,而不是埋了一個地雷給隊友。