zoukankan      html  css  js  c++  java
  • 重构手法之简化条件表达式【2】

    返回总目录

    本小节目录

    3Consolidate Duplicate Conditional Fragments(合并重复的条件片段)

    概要

    在条件表达式的每个分支上有着相同的一段代码。

    将这段重复代码搬到条件表达式之外。

    动机

    如果有一组条件表达式的所有分支都执行了相同的某段代码,将这段代码搬移到条件表达式外面。这样才能更清楚地表明哪些东西随条件的变化而变化、哪些东西保持不变。

    范例

    假如有如下代码:

    class Deal
    {
        public double Price { get; set; }
        private bool IsSpecialDeal()
        {
            //your code here
            return true;
        }
    
        private void Send()
        {
            //your code here
        }
    
        public double GetTotalPrice()
        {
            double total;
            if (IsSpecialDeal())
            {
                total = Price * 0.95;
                Send();
            }
            else
            {
                total = Price * 0.98;
                Send();
            }
            return total;
        }
    }

    由于条件表达式的两个分支都执行了Send()函数,所以将其移到条件表达式的外围:

    class Deal
    {
        public double Price { get; set; }
        private bool IsSpecialDeal()
        {
            //your code here
            return true;
        }
    
        private void Send()
        {
            //your code here
        }
    
        public double GetTotalPrice()
        {
            double total;
            if (IsSpecialDeal())
            {
                total = Price * 0.95;
            }
            else
            {
                total = Price * 0.98;
            }
            Send();
            return total;
        }
    }

    这样的重构手法同时也可以避免重复代码。

    小结

    我们在对待异常时,也是这样做的。如果try块和catch块内都重复执行了同一段代码,可以将其移到finally块内。

    4Remove Control Flag(移除控制标记)

    概要

    在一系列布尔表达式中,某个变量带着“控制标记”(control flag)的作用。

    以break语句或return语句取代控制标记。

    动机

    在一系列条件表达式中,常常会看到用以判断何时停止条件检查的控制标记:

    set done to false

    while not done

      if(condition)

        do something

        set done to true

      next step of loop

    这样的控制标记大大降低了条件表达式的可读性。以break语句或return语句取代控制标记,会带来很大的便利。

    范例:以break取代简单的控制标记

    下列函数用来检查一系列人名之中是否包含两个可疑人物的名字:

    class Person
    {
        public void CheckSecurity(string[] people)
        {
            bool found = false;
            foreach (var person in people)
            {
                if (!found)
                {
                    if (person == "Don")
                    {
                        SendAlert();
                        found = true;
                    }
                    if (person == "John")
                    {
                        SendAlert();
                        found = true;
                    }
                }
            }
        }
    
        private void SendAlert()
        {
    
        }
    }

    这种情况下很容易找出控制标记:当变量found被赋予true时,搜索就结束。这样我们可以引入break语句替换掉对found变量赋值的语句,替换完成后删除控制标记的引用:

    class Person
    {
        public void CheckSecurity(string[] people)
        {
            foreach (var person in people)
            {
                if (person == "Don")
                {
                    SendAlert();
                    break;
                }
                if (person == "John")
                {
                    SendAlert();
                    break;
                }
            }
        }
    
        private void SendAlert()
        {
    
        }
    }

    范例:以return返回控制标记

    我们将上面的例子稍微改动下:

    class Person
    {
        public void CheckSecurity(string[] people)
        {
            string found = string.Empty;
            foreach (var person in people)
            {
                if (found == string.Empty)
                {
                    if (person == "Don")
                    {
                        SendAlert();
                        found = "Don";
                    }
                    if (person == "John")
                    {
                        SendAlert();
                        found = "John";
                    }
                }
            }
            OtherMethod(found);
        }
    
        private void SendAlert()
        {
    
        }
    
        private void OtherMethod(string found)
        {
    
        }
    }

    在这里,变量found做了两件事:既是控制标记,也是运算结果。遇到这种情况,一般都是先把计算found变量的代码提炼到一个独立函数中:

    class Person
    {
        public void CheckSecurity(string[] people)
        {
            string found = FoundMiscreant(people);
            OtherMethod(found);
        }
    
        private string FoundMiscreant(string[] people)
        {
            string found = string.Empty;
            foreach (var person in people)
            {
                if (person == "Don")
                {
                    SendAlert();
                    found = "Don";
                }
                if (person == "John")
                {
                    SendAlert();
                    found = "John";
                }
            }
            return found;
        }
        private void SendAlert()
        {
    
        }
    
        private void OtherMethod(string found)
        {
    
        }
    }

    然后以return语句取代控制语句,并且完全去掉控制标记:

    class Person
    {
        public void CheckSecurity(string[] people)
        {
            string found = FoundMiscreant(people);
            OtherMethod(found);
        }
    
        private string FoundMiscreant(string[] people)
        {
            foreach (var person in people)
            {
                if (person == "Don")
                {
                    SendAlert();
                    return "Don";
                }
                if (person == "John")
                {
                    SendAlert();
                    return "John";
                }
            }
            return string.Empty;
        }
        private void SendAlert()
        {
    
        }
    
        private void OtherMethod(string found)
        {
    
        }
    }

    如果返回值是void,也可以用return语句取代控制标记,只不过是一个空的return。

    小结

    如果以此办法去处理带有副作用的函数,需要先将查询函数和修改函数分离。

    To Be Continued……

  • 相关阅读:
    Android批量插入数据库提升速度(9.9)
    Android中database所在文件夹路径(9.6)
    Eclipse更改默认工作环境编码为UTF-8(9.6)
    Android下Sqlite的使用(9.7)
    Android下ListView的分页(9.6)
    【转】Tarjan算法 资料合集
    【转】BYV--有向图强连通分量的Tarjan算法
    Codeforces Round #403---C题(DFS,树)
    codeforces#403—B题(二分,三分)
    【转】毛虫算法——尺取法
  • 原文地址:https://www.cnblogs.com/liuyoung/p/7887082.html
Copyright © 2011-2022 走看看