在函数设计中,我们常常会遇到一个令人纠结的问题:参数的合法性由谁负责校验?
我们以如下函数为例:
1 2 3 4 5 6 7 8 9 10
| public OmsMockResponse<String> pushBySynRecord(SynRecord synRecord) { ... OmsInboundOrderResponse inbound = getOmsInboundOrder(order.getContainerNo()); if (inbound == null) { return new OmsMockResponse<>(400, "未找到入库单", null); }
OmsInboundExpectedDatePushRequest request = buildRequest(order, inbound); ... }
|
🧩 1. 谁使用,谁负责
这是最基础的原则:
如果你要用某个值,比如调用 inbound.getInboundOrderNo(),你就要保证这个值有效。
因此,buildRequest 要负责检查 inboundOrderNo 是否为空,而不是调用者 pushBySynRecord。
✅ 谁使用字段,谁就对它的存在性和合法性负责。
🧩 2. 谁输出,谁负责
buildRequest 要负责返回一个结构完整、语义清晰的 Request 实例,它就要确保 expectedDate、inboundOrderNo 都不为空,哪怕调用者传了问题数据,也应该 fail fast。
✅ 被调用方有责任保证其输出对象的完整性。
🧩 3. 如果把参数换成基本字段值呢?
我们曾探讨如果将函数签名改为:
1
| buildRequest(String scheduledWarehouseDate, String inboundOrderNo)
|
那么这两个值就变成调用方的直接输入参数,调用者必须明确检查:
1 2 3
| if (StrUtil.isEmpty(inboundOrderNo)) { ... }
|
因为:
✅ 当你传递的是原始值(如String/int),使用它的代码就是最懂它语义的地方,调用者应承担责任。
🧩 4. int vs Integer:如何选择
类型 使用场景
int 业务默认值清晰、内部使用不需要表达“缺省”
Integer 业务字段可以为 null(未赋值、未选择)/ 与数据库字段对应时
举例:
1 2 3 4 5
| public class UserDTO { private Integer age; }
int sum = 0;
|
✅ 总结
函数设计中参数校验职责的判断,并非生硬划分,而是结合语义、职责、契约综合判断:
原则 描述
谁使用谁负责 使用字段的地方负责其有效性
谁输出谁负责 函数必须确保其输出可用性
最小信任原则 被调用方不应信任调用方输入,必要时做 fail-fast 校验
类型语义选择 Integer 适用于业务不确定性表达;int 用于纯粹逻辑场景
最重要的是:保持函数职责清晰,边界明确,遵循契约精神。