C#策略模式在物流计价引擎中的实践与优化
1. 物流价格计算引擎的业务痛点物流行业的价格计算从来都不是简单的数学问题。我在2018年参与某跨境物流系统重构时曾见过最复杂的计费规则文档——足足87页的Excel表格包含首重续重、区域系数、燃油附加费、旺季溢价等12类计费因子。传统if-else堆砌的代码就像打满补丁的旧衣服每次商务谈判后程序员都要通宵改逻辑。2. 策略模式的核心思想策略模式的本质是多态化算法。想象物流公司的计价规则就像乐高积木基础计费模块首重/续重是2x4标准砖特殊附加费偏远地区/特殊包装是异形件。通过Strategy接口定义统一的拼装凹槽CalculateFee方法每个具体策略类都是可插拔的积木单元。关键认知策略模式不是简单的消除if-else而是建立可进化的算法生态。就像物流公司不会因为新增航空运输就重构整个财务系统。3. C#实现的三层架构设计3.1 策略接口定义public interface IShippingStrategy { decimal Calculate(ShippingContext context); // 策略元数据用于动态UI渲染 string StrategyCode { get; } string DisplayName { get; } int Priority { get; } // 策略执行优先级 }3.2 具体策略实现以区域阶梯计价为例public class RegionalTieredStrategy : IShippingStrategy { public string StrategyCode REGIONAL_TIERED; public decimal Calculate(ShippingContext context) { var tier context.Destination.GetPriceTier(); return context.Weight tier.BaseWeight ? tier.BasePrice (context.Weight - tier.BaseWeight) * tier.ExtraPrice : tier.BasePrice; } // 从数据库加载区域配置 private static ListRegionTier LoadTiers() JsonConvert.DeserializeObjectListRegionTier(File.ReadAllText(region_tiers.json)); }3.3 策略组合引擎public class ShippingCalculator { private readonly IEnumerableIShippingStrategy _strategies; public ShippingCalculator(IEnumerableIShippingStrategy strategies) { _strategies strategies.OrderBy(s s.Priority); } public ShippingResult Calculate(ShippingContext context) { var result new ShippingResult(); foreach (var strategy in _strategies) { result.AddFee(strategy.DisplayName, strategy.Calculate(context)); } return result; } }4. 动态策略配置方案4.1 数据库设计CREATE TABLE ShippingStrategies ( Id INT PRIMARY KEY, Code VARCHAR(50) UNIQUE, -- 对应StrategyCode AssemblyName VARCHAR(100), -- 策略所在程序集 ClassName VARCHAR(100), -- 完整类名 IsActive BIT DEFAULT 1, ConfigJson NVARCHAR(MAX) -- 策略特定配置 );4.2 运行时加载// 从数据库加载所有激活策略 var strategies dbContext.ShippingStrategies .Where(s s.IsActive) .Select(s { var type Assembly.Load(s.AssemblyName).GetType(s.ClassName); return (IShippingStrategy)JsonConvert.DeserializeObject( s.ConfigJson, type); }).ToList();5. 性能优化实践5.1 策略缓存方案// 使用MemoryCache避免重复反射 private static readonly MemoryCache _strategyCache new MemoryCache(new MemoryCacheOptions()); public IShippingStrategy GetStrategy(string code) { return _strategyCache.GetOrCreate(code, entry { var config GetStrategyConfigFromDB(code); var strategy CreateStrategyInstance(config); entry.SetSlidingExpiration(TimeSpan.FromMinutes(30)); return strategy; }); }5.2 并行计算优化对于可独立计算的策略var parallelOptions new ParallelOptions { MaxDegreeOfParallelism 3 }; var feeResults new ConcurrentDictionarystring, decimal(); Parallel.ForEach(_strategies, parallelOptions, strategy { feeResults[strategy.DisplayName] strategy.Calculate(context); });6. 测试驱动开发实践6.1 策略单元测试[TestMethod] public void RegionalTieredStrategy_Should_Calculate_Correctly() { // Arrange var strategy new RegionalTieredStrategy(); var context new ShippingContext { Weight 5.2m, Destination new Address { RegionCode EAST_1 } }; // Act var fee strategy.Calculate(context); // Assert Assert.AreEqual(38.6m, fee); // 首重3kg收费20元 2.2kg*8.5元 }6.2 组合策略测试使用Moq框架模拟策略var mockStrategy1 new MockIShippingStrategy(); mockStrategy1.Setup(s s.Calculate(It.IsAnyShippingContext())).Returns(15); var calculator new ShippingCalculator(new[] { mockStrategy1.Object }); var result calculator.Calculate(new ShippingContext()); Assert.AreEqual(15, result.TotalFee);7. 生产环境问题排查7.1 策略执行日志public class LoggingStrategyProxy : IShippingStrategy { private readonly IShippingStrategy _inner; private readonly ILogger _logger; public decimal Calculate(ShippingContext context) { _logger.LogInformation($Executing {_inner.GetType().Name}...); var sw Stopwatch.StartNew(); try { var result _inner.Calculate(context); _logger.LogDebug($Completed in {sw.ElapsedMilliseconds}ms); return result; } catch (Exception ex) { _logger.LogError(ex, $Strategy failed); throw; } } }7.2 常见异常处理循环依赖策略A依赖策略B的结果而策略B又依赖策略A配置缺失新部署的策略缺少必要参数性能劣化某个策略执行时间突然增长10倍8. 领域扩展实践8.1 与规则引擎集成// 使用RulesEngine实现动态条件 public class DiscountRuleStrategy : IShippingStrategy { public decimal Calculate(ShippingContext context) { var workflow new Workflow { Rules LoadDiscountRules() }; var result new RulesEngine.RulesEngine() .Execute(workflow, context); return result.First().Output as decimal? ?? 0; } }8.2 机器学习预测策略public class PredictivePricingStrategy : IShippingStrategy { private readonly IPredictionModel _model; public decimal Calculate(ShippingContext context) { var features new { context.Weight, context.Destination.PostalCode, DateTime.Now.Month }; return _model.Predict(features); } }9. 架构演进建议当策略数量超过50个时建议按业务域划分策略包如StandardShipping.dll、ExpressShipping.dll引入策略分组执行器建立策略版本控制系统开发可视化策略编排界面我在实际项目中验证过的性能数据200个策略并行计算平均响应时间120ms动态加载策略耗时从原始反射的200ms优化到5ms内存占用稳定在50MB以内万次调用