小酌重構系列[14]——使用多態代替條件判斷


概述

有時候你可能會在條件判斷中,根據不同的對象類型(通常是基類的一系列子類,或接口的一系列實現),提供相應的邏輯和算法。
當出現大量類型檢查和判斷時,if else(或switch)語句的體積會比較臃腫,這無疑降低了代碼的可讀性。
另外,if else(或switch)本身就是一個“變化點”,當需要擴展新的對象類型時,我們不得不追加if else(或switch)語句塊,以及相應的邏輯,這無疑降低了程序的可擴展性,也違反了面向對象的OCP原則。

基於這種場景,我們可以考慮使用“多態”來代替冗長的條件判斷,將if else(或switch)中的“變化點”封裝到子類中。這樣,就不需要使用if else(或switch)語句了,取而代之的是子類多態的實例,從而使得代碼的可讀性和可擴展性提高了——這就是本文要介紹的重構策略“使用多態代替條件判斷”。

使用多態代替條件

圖說

這個重構策略比較容易理解,下面這幅圖演示了它的重構過程(綠色表示重構前,紅色表示重構后)。

image_thumb1

這個重構也常見於一些設計模式,例如:“策略者模式”(指對象的某個行為,在某個場景中,該行為有不同的實現算法)。

image_thumb16

示例

重構前

這段代碼定義了4個類,Employee和NonEmployee是Customer的子類,OrderProcessor類根據不同的客戶類型和訂單商品處理訂單折扣。

image_thumb5

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原則。

image_thumb11

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;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM