設計模式之策略模式在地鐵票價系統中的應用
引言
設計模式是面向對象編程的一個非常精彩的部分。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性,它能幫助我們將應用組織成容易了解,容易維護,具有彈性的架構。本文通過一個簡單的案例來講述策略模式在地鐵票價系統中的應用。
案例描述
乘客從一個車站乘坐地鐵到另一個車站,他/她需要購買一張票。鐵路部門對於票價有一些特別的票價規定:
按照市物價主管部門批復的軌道交通網絡票價體系,即:軌道交通實行按裏程計價的多級票價,0~6公裏3元,6公裏之後每10公裏增加1元;票價計算采用最短路徑法,即:當兩個站點之間有超過1條換乘路徑時,選取裏程最短的一條路徑作為兩站間票價計算依據。
案例分析
讓我們考慮有20個站點:1s,2s,3s......20s,並且乘客在不同的場景下乘坐地鐵。為了更清晰的講述問題,我們在原有定價標準上虛擬了一些應用場景。
如果乘客A乘坐的裏程小於6公裏,那麽他將需要支付3元車票費用。
如果乘客B乘坐的裏程大於6公裏,他將需要額外支付超出部分的車票費用,計費標準為6公裏之後每10公裏增加1元。
如果乘客C是VIP客戶,那麽他將在原計費標準上享受9折優惠。
如果後續有一些額外收費或額外優惠,在以上計費基礎上再進行調整。
解決方案
這個問題可以通過使用“策略設計模式”來解決。因為不同類型的票價策略可以基於不同的規則來應用。 以下是票價策略的不同類型:
- 基本票價規則戰略
- VIP票價規則策略
- 額外的票價規則策略
每張票價規則策略將分別寫入票價計算算法,這些算法不會相互幹擾。 新的票價規則可以添加和寫入新的票價規則策略。這種模式也將遵循“對擴展開放、對修改關閉”的理念。
依賴關系圖
類圖
代碼說明
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
作者:阿子博客地址:http://www.cnblogs.com/yayazi/
本文地址:http://www.cnblogs.com/yayazi/p/8350679.html
聲明:本博客原創文字允許轉載,轉載時必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
設計模式之策略模式在地鐵票價系統中的應用