用C++写个出租车计费器:从需求分析到代码实现的完整流程(附测试用例)

用C++写个出租车计费器:从需求分析到代码实现的完整流程(附测试用例)
用C实现出租车计费系统从需求拆解到工程化实践出租车计费系统看似简单却蕴含着软件工程中需求分析、算法设计、边界处理等核心思维。本文将带您从零开始用C构建一个健壮的计费系统并深入探讨工程实践中的关键细节。1. 需求分析与规格定义任何可靠的软件开发都始于清晰的需求分析。让我们先拆解出租车计费的业务规则基础计费规则起步价3公里内10元3-13公里每公里2元超过13公里每公里3元含50%回空补贴等待时间计费每满5分钟加收2元不足5分钟不收费输出要求金额四舍五入到整数输入格式里程(公里小数点后1位) 等待时间(分钟整数)注意实际业务中可能存在夜间费、节假日费等附加规则本例暂不考虑这些扩展场景。2. 系统设计与架构2.1 核心算法设计计费逻辑可以分解为三个独立计算模块// 里程费用计算函数 double calculateDistanceFee(double distance) { if (distance 3) return 10; if (distance 13) return 10 (distance - 3) * 2; return 10 10 * 2 (distance - 13) * 3; } // 等待时间费用计算函数 int calculateWaitingFee(int minutes) { return (minutes / 5) * 2; } // 四舍五入函数 int roundToNearestInt(double value) { return static_castint(value 0.5); }2.2 类设计建议对于更工程化的实现可以考虑封装为类class TaxiMeter { private: const double BASE_DISTANCE 3.0; const double BASE_FEE 10.0; const double MID_RATE 2.0; const double LONG_RATE 3.0; const int WAITING_UNIT 5; const int WAITING_FEE 2; public: double calculateTotalFee(double distance, int waitingMinutes); // 其他辅助方法... };3. 完整代码实现与解析以下是经过工程化改进的完整实现#include iostream #include cmath using namespace std; namespace TaxiCalculator { constexpr double BASE_DISTANCE 3.0; constexpr double BASE_FEE 10.0; constexpr double MID_RATE 2.0; constexpr double LONG_DISTANCE 13.0; constexpr double LONG_RATE 3.0; constexpr int WAITING_UNIT 5; constexpr int WAITING_FEE 2; double calculateDistanceFee(double distance) { if (distance BASE_DISTANCE) { return BASE_FEE; } if (distance LONG_DISTANCE) { return BASE_FEE (distance - BASE_DISTANCE) * MID_RATE; } return BASE_FEE (LONG_DISTANCE - BASE_DISTANCE) * MID_RATE (distance - LONG_DISTANCE) * LONG_RATE; } int calculateWaitingFee(int minutes) { return (minutes / WAITING_UNIT) * WAITING_FEE; } int roundToNearestInt(double value) { return static_castint(value 0.5); } } int main() { double distance; int waitingMinutes; cout 请输入行驶里程(公里)和等待时间(分钟): ; cin distance waitingMinutes; if (distance 0 || waitingMinutes 0) { cerr 错误输入值不能为负数 endl; return 1; } double distanceFee TaxiCalculator::calculateDistanceFee(distance); int waitingFee TaxiCalculator::calculateWaitingFee(waitingMinutes); double totalFee distanceFee waitingFee; int roundedFee TaxiCalculator::roundToNearestInt(totalFee); cout 应付车费: roundedFee 元 endl; return 0; }代码改进亮点使用命名空间封装业务逻辑采用constexpr定义魔法数字添加输入合法性检查更清晰的变量命名分离计算逻辑与I/O操作4. 测试策略与用例设计全面的测试是确保系统可靠性的关键。我们设计以下测试用例测试场景输入(里程, 时间)预期输出测试要点起步价内2.6, 210不足3公里刚好起步价3.0, 010边界值中等距离5.1, 4143-13公里计费长距离12.5, 934超13公里计费等待时间1.0, 5125分钟整零距离0.0, 1010特殊边界四舍五入3.0, 01010.4元应显示103.0, 01110.5元应显示11自动化测试示例#include cassert void runTests() { assert(TaxiCalculator::roundToNearestInt(10.4) 10); assert(TaxiCalculator::roundToNearestInt(10.5) 11); assert(TaxiCalculator::calculateDistanceFee(2.6) 10); assert(TaxiCalculator::calculateDistanceFee(12.5) 31.5); assert(TaxiCalculator::calculateWaitingFee(9) 2); // 更多测试断言... } int main() { runTests(); // 主程序... }5. 工程化扩展思考实际项目中我们还可以考虑以下增强配置化设计struct PricingConfig { double baseDistance; double baseFee; // 其他配置项... }; class ConfigurableTaxiMeter { PricingConfig config; public: ConfigurableTaxiMeter(const PricingConfig cfg) : config(cfg) {} // 计算方法... };日志记录void logTransaction(double distance, int minutes, int fee) { ofstream logfile(transactions.log, ios::app); logfile [ getCurrentTime() ] distance km, minutes min: fee 元 endl; }多城市支持enum class City { Beijing, Shanghai, Guangzhou }; PricingConfig getConfigForCity(City city) { switch(city) { case City::Beijing: return {3.0, 13.0, 10.0, 2.0, 3.0}; // 其他城市配置... } }性能考量对于高频调用的计费服务可以考虑使用查表法预先计算常见里程费用采用内存池减少动态分配实现无锁并发计算6. 常见问题与调试技巧在实际开发中可能会遇到以下典型问题问题1四舍五入结果不符合预期解决方案使用标准库的round函数而非static_cast#include cmath int rounded static_castint(round(value));问题2浮点数精度问题建议使用定点数表示金额#include iomanip cout fixed setprecision(2) amount;问题3边界条件遗漏检查清单负值输入超大数值输入刚好处于计费分段点的值(如3.0、13.0公里)等待时间刚好是5的倍数调试技巧使用条件断点检查特定输入打印中间计算结果单元测试每个计算函数使用Valgrind检查内存问题