我们有一个API函数,可根据给定的开始日期和结束日期将总金额细分为每月金额。
// JavaScript
function convertToMonths(timePeriod) {
// ... returns the given time period converted to months
}
function getPaymentBreakdown(total, startDate, endDate) {
const numMonths = convertToMonths(endDate - startDate);
return {
numMonths,
monthlyPayment: total / numMonths,
};
}
最近,此API的消费者希望以其他方式指定日期范围:1)通过提供月数而不是结束日期,或2)通过提供每月付款并计算结束日期。为此,API小组将功能更改为以下内容:
// JavaScript
function addMonths(date, numMonths) {
// ... returns a new date numMonths after date
}
function getPaymentBreakdown(
total,
startDate,
endDate /* optional */,
numMonths /* optional */,
monthlyPayment /* optional */,
) {
let innerNumMonths;
if (monthlyPayment) {
innerNumMonths = total / monthlyPayment;
} else if (numMonths) {
innerNumMonths = numMonths;
} else {
innerNumMonths = convertToMonths(endDate - startDate);
}
return {
numMonths: innerNumMonths,
monthlyPayment: total / innerNumMonths,
endDate: addMonths(startDate, innerNumMonths),
};
}
我觉得此更改使API复杂化。现在,调用者需要有关隐藏与功能的实现启发式担心在确定哪些参数采取偏好被用来计算日期范围(即根据优先顺序monthlyPayment
,numMonths
,endDate
)。如果调用者不注意函数签名,则他们可能会发送多个可选参数,并对endDate
被忽略的原因感到困惑。我们确实在功能文档中指定了此行为。
另外,我觉得它树立了一个不好的先例,并增加了它不应该关注的API责任(即违反SRP)。假设额外的消费者想要的功能,以支持更多的使用情况,如计算total
从numMonths
和monthlyPayment
参数。随着时间的流逝,该功能将变得越来越复杂。
我的喜好是保持功能不变,而是要求调用者endDate
自行计算。但是,我可能是错的,并且想知道所做的更改是否是设计API函数的可接受方法。
或者,是否存在用于处理此类情况的通用模式?我们可以在API中提供其他高阶函数来包装原始函数,但这会使API膨胀。也许我们可以添加一个额外的标志参数来指定在函数内部使用哪种方法。
monthlyPayment
给定但total
不是整数的情况。如果不能保证这些值是整数(例如,使用total = 0.3
和,请尝试使用它),以及如何处理可能的浮点舍入错误monthlyPayment = 0.1
。