上一篇
Java实现出租车车费计算需按不同里程区间分段计费,结合等候时间规则编写逻辑
需求分析
出租车计价规则通常包含以下要素:
- 起步价(如3公里内固定收费X元)
- 超起步距离后的单价(每增加Y公里加收Z元)
- 夜间附加费/高峰时段溢价(可选复杂化场景)
- 等待时间费用(低速行驶或停车时按分钟计费)
- 四舍五入规则(最终金额保留到整数或一位小数)
为简化模型,我们采用常见标准:
- 起步里程:3公里 → 基础费用10元
- 超出部分:每公里2元
- 无夜间/高峰加成,仅计算行驶距离
算法设计思路
输入输出定义
| 变量名 | 类型 | 说明 |
|---|---|---|
| distance | double | 乘车总距离(单位:公里) |
| totalFee | double | 应收总费用 |
分段计算公式
若 distance <= 3 → totalFee = 10元 否则 → totalFee = 10 + (distance 3) × 2
- 输入2.5km → 输出10元
- 输入5km → 10 + (5-3)2 = 14元
- 输入8.7km → 10 + (8.7-3)2 = 10+11.4=21.4元
Java实现方案
方法1:面向过程风格(静态工具类)
public class TaxiFareCalculator {
private static final double BASE_PRICE = 10.0; // 起步价
private static final double PER_KM_RATE = 2.0; // 每公里费率
private static final double INITIAL_RANGE = 3.0; // 起步覆盖范围(km)
/
计算车费主入口
@param distance 行驶距离(km),必须≥0
@return 总费用(元),保留两位小数
@throws IllegalArgumentException 如果距离无效
/
public static double calculateFare(double distance) {
if (distance < 0) {
throw new IllegalArgumentException("距离不能为负数");
}
if (distance <= INITIAL_RANGE) {
return BASE_PRICE;
} else {
return BASE_PRICE + (distance INITIAL_RANGE) PER_KM_RATE;
}
}
// 格式化显示辅助方法
public static String formattedResult(double fare) {
return String.format("%.2f元", fare);
}
}
使用示例:
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入乘车距离(km): ");
double km = scanner.nextDouble();
try {
double fee = TaxiFareCalculator.calculateFare(km);
System.out.println("应付金额: " + TaxiFareCalculator.formattedResult(fee));
} catch (IllegalArgumentException e) {
System.err.println("错误:" + e.getMessage());
}
}
}
方法2:面向对象封装(推荐工业实践)
创建独立实体类增强可维护性:
class RideProfile {
private final double basePrice; // 基础费用
private final double ratePerKm; // 超出后单价
private final double thresholdKm; // 阈值里程数
public RideProfile(double base, double rate, double limit) {
this.basePrice = base;
this.ratePerKm = rate;
this.thresholdKm = limit;
}
public double computeCost(double distanceTraveled) {
if (distanceTraveled < 0) throw new IllegalStateException("无效里程");
return distanceTraveled <= thresholdKm ? basePrice :
basePrice + (distanceTraveled thresholdKm) ratePerKm;
}
}
// 客户端调用方式
RideProfile standardPricing = new RideProfile(10, 2, 3);
double bill = standardPricing.computeCost(7.5); // => 10+(7.5-3)2=19元
边界测试案例表
| 测试序号 | 输入距离(km) | 预期结果(元) | 备注 |
|---|---|---|---|
| T1 | 0 | 10 | 最小合法值 |
| T2 | 3 | 10 | 刚好达到起步上限 |
| T3 | 1 | 2 | 刚超过起步范围 |
| T4 | 10 | 24 | (10)+(10-3)2=24 |
| T5 | -5 | Exception | 触发异常处理 |
| T6 | 7 | 4 | 浮点精度验证 |
进阶优化方向
-
多城市策略支持
通过配置文件管理不同城市的计价规则:# beijing.properties base=13.0 perkm=2.3 freerange=3.5
动态加载实现国际化适配。
-
复合计费模式叠加
添加以下维度扩展:- 低速等待费:速度<20km/h时按分钟计费
- 动态调价因子:工作日早晚高峰×1.5系数
- 远程回空补贴:单程>50km额外奖励司机
-
货币本地化格式
使用NumberFormat类实现地区特定的金额显示:Locale usLocale = new Locale("en", "US"); NumberFormat nf = NumberFormat.getCurrencyInstance(usLocale); System.out.println(nf.format(21.4)); // "$21.40"
完整控制台应用程序模板
import java.util.InputMismatchException;
import java.util.Scanner;
public class InteractiveTaxiMeter {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
while (true) {
System.out.println("n===出租车计价器===");
System.out.print("请输入行驶距离(km)[输入q退出]: ");
String input = console.nextLine().trim();
if (input.equalsIgnoreCase("q")) break;
try {
double km = Double.parseDouble(input);
double charge = calculateOptimized(km);
System.out.printf("行程%.1f公里,应付金额: %.2f元%n", km, charge);
} catch (NumberFormatException e) {
System.err.println("️ 请输入有效的数字!");
} catch (IllegalArgumentException msg) {
System.err.println(" " + msg.getMessage());
}
}
console.close();
}
private static double calculateOptimized(double distance) {
validateDistance(distance); // 前置校验分离出来提高复用性
return distance <= 3 ? 10 : 10 + (distance 3) 2;
}
private static void validateDistance(double d) {
if (d < 0) throw new IllegalArgumentException("距离不可为负!");
if (Double.isNaN(d)) throw new IllegalArgumentException("非有效数值");
}
}
FAQs
Q1: 如果乘客绕路导致实际行驶距离大于导航预估怎么办?
A: 本程序严格按实际行驶距离计费,建议结合GPS轨迹分析实现防科技机制,例如对比路线规划引擎获取的理论最短路径与实测路径差异率超过阈值时发出警告。
Q2: 如何修改代码以支持分段累进制收费?(如前3km后每5km涨价一次)
A: 可将计费拆分为多个区间段处理:
public static double progressiveRate(double km) {
double[] breaks = {3, 8, 15}; // 分段节点
double[] rates = {10, 15, 20}; // 对应区间的单价增幅
double sum = 0;
for (int i=0; i<breaks.length; i++) {
if (km > breaks[i]) {
sum += (breaks[i] (i==0?0:breaks[i-1])) rates[i];
} else break;
}
return sum; // 需补充剩余未完成的最末段
