设计模式是面向对象编程的一个非常精彩的部分。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性,它能帮助我们将应用组织成容易了解,容易维护,具有弹性的架构。本文通过一个简单的案例来讲述策略模式在地铁票价系统中的应用。
案例描述乘客从一个车站乘坐地铁到另一个车站,他/她需要购买一张票。铁路部门对于票价有一些特别的票价规定:
按照市物价主管部门批复的轨道交通网络票价体系,即:轨道交通实行按里程计价的多级票价,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折扣价。
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身份,那么他/她将得到享受特殊的优惠。这个类实现了这个算法。
OtherRuleFareCalculator类
这个类实现的是其他额外的费用或优惠票价的算法。一些额外的价格将被添加到总费用中。额外的价格可以是附加收费(正值),也可以是额外折扣(负值)。
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; } } }