2021-10-16 11:51

重構基礎-邏輯反相

利用程式具有區段的能力,我們可以將 [如果 A 成立就做 B] 轉換成 [如果 A 不成立就離開],用這個方式做邏輯反相可以讓原本看似複雜的程式簡化很多,讓程式變得清晰思慮也會變的清晰,困難的問題就變得簡單,或著就不在是問題了。

這是一段重構前的程式:

foreach (var item in list)
{
    Guid guid = new Guid(item.project_GUID.Value.ToString());
    var project = _dc.Project.FirstOrDefault(w => w.ProjectID == guid);
    if (project != null)
    {
        var mails = !String.IsNullOrEmpty(project.AlertEmail) ? project.AlertEmail.Split(new char[]{';'}) : null;
        if (mails != null)
        {
            if(!mails.Any(x => x.mail == "a@b.c"))
            {
                foreach (var mail in mails)
                {
                    if (!mailDic.ContainsKey(mail.Trim()))
                        mailDic.Add(mail, new List<int>());

                    mailDic[mail].Add(item.projectID);
                }

            }
        }
    }
}

將邏輯反相重構後的程式:

foreach (var item in list)
{
    Guid guid = new Guid(item.project_GUID.Value.ToString());
    var project = _dc.Project.FirstOrDefault(w => w.ProjectID == guid);
    if (project == null) { continue; }

    if (String.IsNullOrEmpty(project.AlertEmail)) { continue; }

    var mails = project.AlertEmail.Split(new char[]{';'});
    if(mails.Any(x => x.mail == "a@b.c")){ continue; }

    foreach (var mail in mails)
    {
        if (!mailDic.ContainsKey(mail.Trim()))
        { mailDic.Add(mail, new List<int>()); }

        mailDic[mail].Add(item.projectID);
    }
}

可以看出程式的縮排階層減少了,也簡化了程式的複雜度,重構的方法就是將 if 反相將 else 前移,也許一開始很難用這種方式寫程式,但是人腦是可以訓練的,在每次重構時進行調整改寫,習慣這種模式後很自然就會用這種[跳離]的思維去寫程式邏輯了。

當然這種方式也是有缺點的,就是有時候不這麼直覺會不好理解,但是可以增加一些註解來輔助描述,或是拆分判斷條件例如:

if (a != null || b == null) { return; }

/* 這可以拆分成兩行,不用拘泥一行完成 */

if (a != null) { return; }
if (b == null) { return; }

程式邏輯有一個有趣的事,往往用正向邏輯無法處理的問題,改用反相邏輯就會簡單很多,例如:需要用特定的邏輯尋找符合的項目,可能因為那個特定邏輯讓效能非常的差,這時候如果改用不符合特定邏輯的項目排除,留下來的就會是符合的項目,因為是用消去法所以要尋找的數量會越算越少,所以執行效能會收斂。

0 回應: