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

来源:http://www.cnblogs.com/keepfool/archive/2016/05/15/5495548.html
-Advertisement-
Play Games

概述 有時候你可能會在條件判斷中,根據不同的對象類型(通常是基類的一系列子類,或介面的一系列實現),提供相應的邏輯和演算法。當出現大量類型檢查和判斷時,if else(或switch)語句的體積會比較臃腫,這無疑降低了代碼的可讀性。另外,if else(或switch)本身就是一個“變化點”,當需要擴... ...


概述

有時候你可能會在條件判斷中,根據不同的對象類型(通常是基類的一系列子類,或介面的一系列實現),提供相應的邏輯和演算法。
當出現大量類型檢查和判斷時,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;
    }
}
【關註】keepfool
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 摘要:本文介紹了簡單工廠模式的概念,優缺點,實現方式,以及結合Annotation和反射的改良方案(讓簡單工廠模式不簡單)。同時介紹了簡單工廠模式(未)遵循的OOP原則。最後給出了簡單工廠模式在JDBC中的應用 原創文章。同步自作者個人博客 "http://www.jasongj.com/desig ...
  • "設計模式系列目錄" 新博客 "wossoneri.com" 單一職責原則 Single Responsibility Principle SRP 就一個類而言,應該僅有一個引起它變化的原因。 假設現在要在iPhone上做一個圖片編輯工具。功能有裁剪圖片,旋轉圖片,縮放移動照片等等。 吶,我們可以寫 ...
  • 利用繼承來提供對象的行為,會導致: 1、代碼在多個子類中重覆 2、很難知道所有鴨子的全部行為 3、運行時的行為不易改變 4、改變會牽一發而動全身,造成其他鴨子不想要的改變 設計原則 1 :找出應用之中可能需要變化之處,把他們獨立出來,不要和那些不需要變化的代碼混在一起。 註釋:把會變化的部分取出並“ ...
  • (原文地址:http://www.cnblogs.com/hellohuang/p/5492302.html ) 這是一個簡單實現有分步式框架,由5個服務進程組成一個伺服器,它們分別是世界服(Ws),資料庫處理服(Dp),場景服(Ss),網關服(Fep),框架的思想用來自工作項目框架(但沒有它的代碼 ...
  • 前段時間因為“某度競價排名”的事情鬧得沸沸揚揚的,因為某度搜出來的內容的質量實在是不敢恭維,所以早就戒掉了某度改用Google了。但是Google早就被牆了呢,所以翻牆才能訪問Google呢,這個“翻牆”的過程就是一個代理的過程。“代理模式”在之前的博客中不止一次的提及過,之前的委托回調就是代理模式 ...
  • 一、簡介Dubbo是Alibaba開源的分散式服務框架,它最 大的特點是按照分層的方式來架構,使用這種方式可以使各個層之間解耦合(或者最大限度地 松耦合)。從服務模型的角度來看,Dubbo採用的是一種非常簡單的模型,要麼是提供方提供服務,要麼是消費方消費服務,所以基於這一點可以抽象出服務提 供方(P ...
  • 觀察者模式:在對象之間定義一對多的依賴,這樣一來,當一個對象改變狀態,依賴它的對象都會收到通知,並自動更新。 舉個例子:氣象監測應用 此系統的三個部分是氣象站(獲取實際氣象數據的物理裝置)、WeatherData對象(追蹤來自氣象站的數據,並更新佈告板)和佈告板(有三個佈告板,一個用來顯示目前天氣狀 ...
  • 新博客 "wossoneri.com" " 設計模式系列目錄 " 需求情景 比如現在需要做一個收銀軟體,要根據用戶所買商品的單價和數量進行計算。 很簡單,用“單價 數量”即可。 但如果某天需要打折呢? 也很簡單,同一個方法,把折扣作為一個參數,預設值為1,代碼改為“單價 數量 折扣”即可。 恩,看起 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...