iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 9
0

同樣一個需求每個人可能採取不一樣的做法。在Sum consecutives的例子中,題目是傳入一組數字陣列,並輸出另一組數字陣列,輸出的數字陣列會把連續的數字加起來(如下圖)。

以下是兩種不同的實作方式
第一種做法

public List<int> SumConsecutives(List<int> numbers)
{
    var consecutiveSums = new List<int>();
    int? lastNumber = null;
    foreach (var number in numbers)
    {
        if (number == lastNumber)
        {
            consecutiveSums[consecutiveSums.Count - 1] += number;
        }
        else
        {
            consecutiveSums.Add(number);
        }
    
        lastNumber = number;
    }
    
    return consecutiveSums;
}

另一種做法

public List<int> SumConsecutives(List<int> numbers)
{
    var consecutiveSums = new List<int>();
    for (var index = 0; index < numbers.Count; index++)
    {
        var consecutiveNumbers = new List<int>{numbers[index]};
        while (index != numbers.Count - 1 && numbers[index] == numbers[index+1])
				{
            consecutiveNumbers.Add(numbers[index]);
            index++;
        }
        consecutiveSums.Add(consecutiveNumbers.Sum());
    }
    
    return consecutiveSums;
}

每一個作法代碼並不長,大約不到二十行。但是如果想要仔細理解每個作法的邏輯,需要花上一些時間。比如第二個作法中的兩層迴圈,就會比較難理解。每個人的思考迴路不盡相同,閱讀代碼時需要一行一行的讀,慢慢的腦中架構出這個做法的思考方式。

當邏輯複雜或方法比較長的時候,很多時候可以透過抽取方法,讓方法名稱描述的目的,把方法實作方式隱藏起來,讓閱讀時可以專注在方法內容。

public List<int> SumConsecutives(List<int> numbers)
{
    var consecutiveSums = new List<int>();
    for (var index = 0; index < numbers.Count; )
    {
        var consecutiveNumbers = GetConsecutiveNumbers(numbers, index);
        consecutiveSums.Add(consecutiveNumbers.Sum());
        index += consecutiveNumbers.Count;
    }
    
    return consecutiveSums;
}

private List<int> GetConsecutiveNumbers(List<int> numbers, int index)
{
    var consecutiveNumbers = new List<int> {numbers[index]};
    while (!IsLastNumber(numbers, index) && IsNumberConsecutive(numbers, index))
    {
        consecutiveNumbers.Add(numbers[index]);
        index++;
    }
    return consecutiveNumbers;
}

private static bool IsNumberConsecutive(List<int> numbers, int index)
{
    return numbers[index] == numbers[index + 1];
}

private bool IsLastNumber(List<int> numbers, int index)
{
    return index == numbers.Count - 1;
}

方法名稱就好像書本最前面的大綱,先用一個章節標題給閱讀的人一些概念,當讀者進到章節裡面時,才把概念化為更詳盡的實作。當往下進到方法裡面時,有助於更快理解裡面的for迴圈、while迴圈的邏輯表達的流程。把方法拆小之後,也有助於優化,關於這個部分,明天繼續使用這個例子調整,讓方法更加簡潔。

閱讀代碼就像在閱讀一本書,章節裡面有小節,小節裡面又有段落。那段落小節章節都是一種抽象,能更好的輔助閱讀。轉到閱讀代碼的情境,把一長串邏輯拆成小段小段的邏輯並花一些時間思考好的方法名稱,也是有效提高閱讀效率的一種方式。


上一篇
Day 8 消除常見迴圈
下一篇
Day 10 抽象之後
系列文
在Kata中尋找Clean Code是否搞錯了什麼30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言