Spiga

标签为重构的文章

一天一个重构方法(19):以异常代替错误码

2009-07-25 20:25:00

摘要:Replace Error Code with Exception:以异常代替错误码 某个函数返回一个特定的代码,用以表示某种错误情况,请改用异常。 public int Withdraw(int amount) { if (amount _balance) return -1; else { _balance -= amount; return 0; } } 改成异常后的代码 public void Withdraw(int amount) { if (amount _balance) throw new Exception(); _balance -= amount; } 异常,这种方式之所以更好,因为它清楚地将普通程序和错误处理分开了,这使得程序更容易理解。我坚信:代码的可理解性应该是我们追求的目标。 阅读全文

一天一个重构方法(18):引入参数对象

2009-07-22 05:07:01

摘要:Introduce Parameter Object:引入参数对象 某些参数总是很自然地同时出现,以一个对象取代这些参数 这个重构方法也很简单,我同样就不举例了。 阅读全文

一天一个重构方法(17):尽早返回

2009-07-02 19:23:29

摘要:Return ASAP:尽早返回 该话题实际上是诞生于移除箭头反模式重构之中。在移除箭头时,它被认为是重构产生的副作用。为了消除箭头,你需要尽快地return。 public class Order { public Customer Customer { get; private set; } public decimal CalculateOrder(Customer customer, IEnumerableProduct products, decimal discounts) { Customer = customer; decimal orderTotal = 0m; if (products.Count() 0) { orderTotal = products.Sum(p = p.Price); if (discounts 0) { orderTotal -= discounts; } } return orderTotal; } } 该重构的理念就是,当你知道应该处理什么并且拥有全部需要的信息之后,立即退出所在方法,不再继续执行。 public class Order { public Customer Customer { get; private set; } public decimal CalculateOrder(Customer customer, IEnumerableProduct products, decimal discounts) { Customer = customer; decimal orderTotal = 0m; if (products.Count() == 0) return 0m; orderTotal = products.Sum(p = p.Price); if (discounts = 0) return orderTotal; orderTotal -= discounts; return orderTotal; } } 阅读全文

一天一个重构方法(16):消除双重否定

2009-06-20 01:57:34

摘要:Remove Double Negative:删除双重否定 尽管我在很多代码中发现了这种严重降低可读性并往往传达错误意图的坏味道,但这种重构本身还是很容易实现的。这种毁灭性的代码所基于的假设导致了错误的代码编写习惯,并最终导致bug。如下例所示: public class Order { public void Checkout(IEnumerableProduct products, Customer customer) { if (!customer.IsNotFlagged) { // the customer account is flagged // log some errors and return return; } // normal order processing } } public class Customer { public decimal Balance { get; private set; } public bool IsNotFlagged { get { return Balance 30m; } } } 如你所见,这里的双重否定十分难以理解,我们不得不找出什么才是双重否定所要表达的肯定状态。修改代码是很容易的。如果我们找不到肯定的判断,可以添加一个处理双重否定的假设,而不要在得到结果之后再去验证。 public class Order { public void Checkout(IEnumerableProduct products, Customer customer) { if (customer.IsFlagged) { // the customer account is flagged // log some errors and return return; } // normal order processing } } public class Customer { public decimal Balance { get; private set; } public bool IsFlagged { get { return Balance = 30m; } } } 阅读全文

一天一个重构方法(15):用显式方法替换参数

2009-06-12 04:26:49

摘要:你有一个方法,其内部完全取决于参数值而采取不同反应,针对该参数的每一个可能值,建立一个独立方法。 public void SetValue(string name, int value) { if (name.Equals(Height)) { _height = value; return; } if (name.Equals(Width)) { _width = value; return; } } 重构之后变成两个函数,从函数名就能知道函数的功能了,而不用多传一个参数 public void SetHeight(int height) { _height = height; } public void SetWidth(int width) { _width = width; } 该重构方法恰恰相反于Parameterize Method。如果某个参数有离散取值,而方法内又以条件式检查这些参数值,并根据不同参数值做出不同的反应,那么就应该使用本重构。调用者原本必须赋予参数使用,以决定方法做出何种响应;现在,你提供了不同的方法给调用者使用,就可以避免出现条件式。但是,如果参数值不会对方法行为有太多影响,就不应该使用本重构。这种情况下就只需要通过参数为一个字段赋值,那么直接使用set属性就行了。如果你的确需要条件判断式行为,那可以先不考虑该重构。 阅读全文

一天一个重构方法(14):参数化方法

2009-06-07 03:23:21

摘要:Parameterize Method:另方法携带参数 若干方法做了类似的工作,但在方法本体中却包括了不同的值,可以建立单一方法,以参数表达那些不同的值。 先看一个简单的例子: public void TenPercentRaise() { salary *= 1.1; } public void FivePercentRaise() { salary *= 1.05; } 这段代码可以替换如下: public void Raise(double factor) { salary *= (1 + factor); } 上面的那个例子太简单,所有人都能做到。下面是一个稍微复杂一点的例子: public double BaseCharge() { double result = Math.Min(LastUsage(), 100) * 0.03; if (LastUsage() 100) { result += (Math.Min(LastUsage(), 200) - 100) * 0.05; } if (LastUsage() 200) { result += (LastUsage() - 200) * 0.07; } return result; } 上述代码可以替换如下: public double BaseCharge() { double result = UsageInRange(0, 100) * 0.03; result += UsageInRange(100,200) * 0.05; result += UsageInRange(200, int.MaxValue) * 0.07; return result; } private int UsageInRange(int start, int end) { if (LastUsage() start) return Math.Min(LastUsage(), end) - start; return 0; } 本项重构的技巧在于:以可将少量数值视为参数为依据,找出带有重复性的代码。 阅读全文

一天一个重构方法(13):删除箭头反模式

2009-06-04 06:01:51

摘要:Remove Arrowhead Antipattern:删除箭头反模式 简单地说,当你使用大量的嵌套条件判断时,形成了箭头型的代码,这就是箭头反模式(arrowheadantipattern)。我经常在不同的代码库中看到这种现象,这提高了代码的圈复杂度(cyclomatic complexity)。下面的例子演示了箭头反模式: public class Security { public ISecurityChecker SecurityChecker { get; set; } public Security(ISecurityChecker securityChecker) { SecurityChecker = securityChecker; } public bool HasAccess(User user, Permission permission, IEnumerablePermission exemptions) { bool hasPermission = false; if (user != null) { if (permission != null) { if (exemptions.Count() == 0) { if (SecurityChecker.CheckPermission(user, permission) || exemptions.Contains(permission)) { hasPermission = true; } } } } return hasPermission; } } 移除箭头反模式的重构和封装条件判断一样简单。这种方式的重构在方法执行之前往往会评估各个条件,下面是重构之后的代码: public class Security { public ISecurityChecker SecurityChecker { get; set; } public Security(ISecurityChecker securityChecker) { SecurityChecker = securityChecker; } public bool HasAccess…… 阅读全文

一天一个重构方法(12):删除参数

2009-06-01 13:06:57

摘要:Remove Parameter:删除参数 本体方法不再需要某个参数,将该参数去除。 参数指出函数所需信息,不同的参数值代表不同的意义。函数调用者必须为每个参数操心该传什么东西进去。如果你不去掉多余参数,你就是让你的每一位用户多费一份心。 应用这个重构你只需删除不在需要的参数即可。简单吧。我就不举例了。 阅读全文

一天一个重构方法(11):添加参数

2009-05-31 20:25:47

摘要:Add Parameter:添加参数 某个方法需要从调用端得到更多信息,为此方法添加一个对象参数,让该对象带进方法所需信息。 应用这个重构你只需多加入一些参数即可。简单吧。我就不举例了。 阅读全文

一天一个重构方法(10):重命名方法

2009-05-30 05:28:35

摘要:Rename Method:重命名方法 我们对方法/类/参数的命名往往不那么合适,以至于误导阅读者对于方法/类/参数功能的理解,我们应该**修改成合适的名称。这个重构看起来简单,但却十分重要。 应用这个重构你只需随手将名称修改得更具描述性、更容易传达其含义即可。简单吧。我就不举例了。 阅读全文