設計模式是面向對象編程的一個很是精彩的部分。使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性,它能幫助咱們將應用組織成容易瞭解,容易維護,具備彈性的架構。本文經過一個簡單的案例來說述策略模式在地鐵票價系統中的應用。html
乘客從一個車站乘坐地鐵到另外一個車站,他/她須要購買一張票。鐵路部門對於票價有一些特別的票價規定:git
按照市物價主管部門批覆的軌道交通網絡票價體系,即:軌道交通實行按里程計價的多級票價,0~6千米3元,6千米以後每10千米增長1元;票價計算採用最短路徑法,即:當兩個站點之間有超過1條換乘路徑時,選取里程最短的一條路徑做爲兩站間票價計算依據。github
讓咱們考慮有20個站點:1s,2s,3s......20s,而且乘客在不一樣的場景下乘坐地鐵。爲了更清晰的講述問題,咱們在原有訂價標準上虛擬了一些應用場景。算法
若是乘客A乘坐的里程小於6千米,那麼他將須要支付3元車票費用。編程
若是乘客B乘坐的里程大於6千米,他將須要額外支付超出部分的車票費用,計費標準爲6千米以後每10千米增長1元。設計模式
若是乘客C是VIP客戶,那麼他將在原計費標準上享受9折優惠。網絡
若是後續有一些額外收費或額外優惠,在以上計費基礎上再進行調整。架構
這個問題能夠經過使用「策略設計模式」來解決。由於不一樣類型的票價策略能夠基於不一樣的規則來應用。 如下是票價策略的不一樣類型:this
每張票價規則策略將分別寫入票價計算算法,這些算法不會相互干擾。 新的票價規則能夠添加和寫入新的票價規則策略。這種模式也將遵循「對擴展開放、對修改關閉」的理念。spa
依賴關係圖
類圖
代碼說明
IFareStrategy接口
這個接口定義了票價計算的經常使用策略,實現一個類能夠實現基於上下文的票價算法。
using TrainFair.Models; namespace TrainFair.FareCalculator { public interface IFareStrategy { float GetFare(IFareRule ruleValues, float basicFare); } }
FareConstants類
FareConstants定義了計費的規則,包括起步價,超出里程遞增價及VIP折扣價。
namespace TrainFair.Constants { public class FareConstants { public const float BasicFare = 3.0F; public const float OnStationFare = 1.0F; public const float VIPDiscount = 0.1F; } }
StationRuleFareCalculator類
StationRuleFareCalculator類根據行駛的車站裏程和問題陳述部分定義的一些規則集來計算車費。
using System; using TrainFair.Models; namespace TrainFair.FareCalculator { public class StationRuleFareCalculator : IFareStrategy { public float GetFare(IFareRule ruleValues, float basicFare) { var stationFareRuleModel = ruleValues as StationFareRuleModel; if (stationFareRuleModel == null || stationFareRuleModel.StationDistance <= 0.0f) return 0; if (stationFareRuleModel.StationDistance < 6) return basicFare; int restChargingStations = (int)Math.Ceiling((stationFareRuleModel.StationDistance - 6.0f)/10.0f); var totalFare = basicFare + restChargingStations * stationFareRuleModel.IncrementalPrice; return totalFare; } } }
VIPRuleFareCalculator類
這個類實現的是VIP的票價算法。若是乘客是VIP身份,那麼他/她將獲得享受特殊的優惠。這個類實現了這個算法。
using TrainFair.Models; namespace TrainFair.FareCalculator { public class VIPRuleFareCalculator : IFareStrategy { public float GetFare(IFareRule ruleValues, float basicFare) { var vipFareRuleModel = ruleValues as VIPFareRuleModel; if (vipFareRuleModel == null) return 0; var totalFare = basicFare - (basicFare * vipFareRuleModel.Discount); return totalFare; } } }
OtherRuleFareCalculator類
這個類實現的是其餘額外的費用或優惠票價的算法。一些額外的價格將被添加到總費用中。額外的價格能夠是附加收費(正值),也能夠是額外折扣(負值)。
using TrainFair.Models; namespace TrainFair.FareCalculator { public class OtherRuleFareCalculator : IFareStrategy { public float GetFare(IFareRule ruleValues, float basicFare) { var otherFareRuleModel = ruleValues as OtherFareRuleModel; if (otherFareRuleModel == null) return basicFare; float totalFare = basicFare + otherFareRuleModel.AdditionalFare; return totalFare; } } }
FareRuleCalculatorContext類
using TrainFair.Models; namespace TrainFair.FareCalculator { public class FareCalculatorContext { private readonly IFareStrategy _fareStrategy; public FareCalculatorContext(IFareStrategy fareStrategy) { this._fareStrategy = fareStrategy; } public float GetFareDetails(IFareRule fareRules, float basicFare) { return _fareStrategy.GetFare(fareRules, basicFare); } } }
代碼結構裏有一些基於車站票價,VIP票價,額外票價等狀況的model類。
IFareRule接口
這是基本票價規則模型接口,每一個模型類都實現它。
namespace TrainFair.Models { public interface IFareRule { int FareRuleId { get; set; } } }
StationFareRuleModel類
這個類定義的是車站票價規則的基本屬性。
namespace TrainFair.Models { public class StationFareRuleModel : IFareRule { public int FareRuleId { get; set; } public int StationsCounts { get; set; } public float IncrementalPrice { get; set; } public float StationDistance { get; set; } } }
VIPFareRuleModel類
這個類定義了VIP折扣的屬性。
namespace TrainFair.Models { public class VIPFareRuleModel : IFareRule { public int FareRuleId { get; set; } public float Discount { get; set; } } }
OtherFareRuleModel類
這個類定義其餘額外收費的屬性。
namespace TrainFair.Models { public class OtherFareRuleModel : IFareRule { public int FareRuleId { get; set; } public string OtherFareName { get; set; } public float AdditionalFare { get; set; } } }
模型的屬性能夠根據將來的需求進行加強和調整,並能夠靈活應用在算法類中。
執行結果
如下是控制檯輸出:
本文結尾附上了程序代碼。
車站基礎票價、VIP票價、額外票價等不一樣類型的票價計算規則是不一樣的,全部的算法都被分解到不一樣的類中,以便可以在運行時選擇不一樣的算法。策略模式的用意是針對一組算法或邏輯,將每個算法或邏輯封裝到具備共同接口的獨立的類中,從而使得它們之間能夠相互替換。策略模式使得算法或邏輯能夠在不影響到客戶端的狀況下發生變化。說到策略模式就不得不說起OCP(Open Closed Principle) 開閉原則,即對擴展開放,對修改關閉。策略模式的出現很好地詮釋了開閉原則,有效地減小了分支語句。
程序代碼:https://github.com/daivven/TrainFair