概述 有時候你可能會在條件判斷中,根據不同的對象類型(通常是基類的一系列子類,或介面的一系列實現),提供相應的邏輯和演算法。當出現大量類型檢查和判斷時,if else(或switch)語句的體積會比較臃腫,這無疑降低了代碼的可讀性。另外,if else(或switch)本身就是一個“變化點”,當需要擴... ...
概述
有時候你可能會在條件判斷中,根據不同的對象類型(通常是基類的一系列子類,或介面的一系列實現),提供相應的邏輯和演算法。
當出現大量類型檢查和判斷時,if else(或switch)語句的體積會比較臃腫,這無疑降低了代碼的可讀性。
另外,if else(或switch)本身就是一個“變化點”,當需要擴展新的對象類型時,我們不得不追加if else(或switch)語句塊,以及相應的邏輯,這無疑降低了程式的可擴展性,也違反了面向對象的OCP原則。
基於這種場景,我們可以考慮使用“多態”來代替冗長的條件判斷,將if else(或switch)中的“變化點”封裝到子類中。這樣,就不需要使用if else(或switch)語句了,取而代之的是子類多態的實例,從而使得代碼的可讀性和可擴展性提高了——這就是本文要介紹的重構策略“使用多態代替條件判斷”。
使用多態代替條件
圖說
這個重構策略比較容易理解,下麵這幅圖演示了它的重構過程(綠色表示重構前,紅色表示重構後)。
這個重構也常見於一些設計模式,例如:“策略者模式”(指對象的某個行為,在某個場景中,該行為有不同的實現演算法)。
示例
重構前
這段代碼定義了4個類,Employee和NonEmployee是Customer的子類,OrderProcessor類根據不同的客戶類型和訂單商品處理訂單折扣。
隱藏代碼public abstract class Customer { } public class Employee : Customer { } public class NonEmployee : Customer { } public class OrderProcessor { public decimal ProcessOrder(Customer customer, IEnumerable<Product> products) { // do some processing of order decimal orderTotal = products.Sum(p => p.Price); Type customerType = customer.GetType(); if (customerType == typeof(Employee)) { orderTotal -= orderTotal * 0.15m; } else if (customerType == typeof(NonEmployee)) { orderTotal -= orderTotal * 0.05m; } return orderTotal; } }
可以看到,ProcessOrder()
方法的可讀性較差,也比較難以維護。
如果某些客戶類型不再使用了,它裡面的一些分支判斷就變成了無效的代碼。
如果擴展新的客戶類型,ProcessOrder()
方法的邏輯需要變更,if else語句塊也會越來越大。
我們使用多態代替條件判斷來重構。
重構後
重構後,由於DiscountPercentage封裝在Customer類和其子類中了,所以ProcessOrder()
方法就無需去判定customer對象的真正類型了。
即使擴展新的Customer類型,ProcessOrder()
方法也不用修改,而只需要繼承Customer類並實現DiscountPercentage屬性,這也符合面向對象的OCP原則。
public abstract class Customer { public abstract decimal DiscountPercentage { get; } } public class Employee : Customer { public override decimal DiscountPercentage { get { return 0.15m; } } } public class NonEmployee : Customer { public override decimal DiscountPercentage { get { return 0.05m; } } } public class OrderProcessor { public decimal ProcessOrder(Customer customer, IEnumerable<Product> products) { // do some processing of order decimal orderTotal = products.Sum(p => p.Price); orderTotal -= orderTotal * customer.DiscountPercentage; return orderTotal; } }【關註】keepfool