同一个特效槽位被释放后,稍后可以交给新的对象使用。如果旧消息只记住槽号,延迟到达时就可能误操作新对象;在标识中增加代次能区分两次使用。
本篇给出一份完整且可重复的虚构游戏记录。先读清规则,再尝试自行推演输入,最后逐项对照中间状态。不同作品可以选择不同约定,只有在相同前提下才能比较结果;不要只看最终数字相同就认为过程正确。
约定与原始记录
三个槽位初始空闲且代次为零。创建使用最小空闲槽,并将其代次加一;读取或释放必须同时匹配槽号、代次和占用状态。失效请求只返回失败,不修改任何槽。这里的代次整数不回绕。
[['创建', None], ['释放', [0, 1]], ['创建', None], ['读取', [0, 1]], ['释放', [0, 1]], ['读取', [0, 2]], ['读取', [1, 2]], ['创建', [1, 4]], ['读取', [2, 1]], ['释放', [1, 4]], ['创建', [2, 3]], ['创建', [1, 3]], ['释放', [2, 1]], ['创建', [0, 4]], ['读取', [0, 4]], ['释放', [1, 1]], ['释放', [2, 2]], ['释放', [1, 4]]]
逐步计算
执行创建,结果True,新凭据[0, 1];槽位代次[1, 0, 0],占用标记[True, False, False]。
执行释放[0, 1],结果True,新凭据None;槽位代次[1, 0, 0],占用标记[False, False, False]。
执行创建,结果True,新凭据[0, 2];槽位代次[2, 0, 0],占用标记[True, False, False]。
执行读取[0, 1],结果False,新凭据None;槽位代次[2, 0, 0],占用标记[True, False, False]。
执行释放[0, 1],结果False,新凭据None;槽位代次[2, 0, 0],占用标记[True, False, False]。
执行读取[0, 2],结果True,新凭据None;槽位代次[2, 0, 0],占用标记[True, False, False]。
执行读取[1, 2],结果False,新凭据None;槽位代次[2, 0, 0],占用标记[True, False, False]。
执行创建,结果True,新凭据[1, 1];槽位代次[2, 1, 0],占用标记[True, True, False]。
执行读取[2, 1],结果False,新凭据None;槽位代次[2, 1, 0],占用标记[True, True, False]。
执行释放[1, 4],结果False,新凭据None;槽位代次[2, 1, 0],占用标记[True, True, False]。
执行创建,结果True,新凭据[2, 1];槽位代次[2, 1, 1],占用标记[True, True, True]。
执行创建,结果False,新凭据None;槽位代次[2, 1, 1],占用标记[True, True, True]。
执行释放[2, 1],结果True,新凭据None;槽位代次[2, 1, 1],占用标记[True, True, False]。
执行创建,结果True,新凭据[2, 2];槽位代次[2, 1, 2],占用标记[True, True, True]。
执行读取[0, 4],结果False,新凭据None;槽位代次[2, 1, 2],占用标记[True, True, True]。
执行释放[1, 1],结果True,新凭据None;槽位代次[2, 1, 2],占用标记[True, False, True]。
执行释放[2, 2],结果True,新凭据None;槽位代次[2, 1, 2],占用标记[True, False, False]。
执行释放[1, 4],结果False,新凭据None;槽位代次[2, 1, 2],占用标记[True, False, False]。
最后代次[2, 1, 2]、占用[True, False, False],失效请求均未改变新对象的状态。
复核方法与适用范围
为每次成功创建单独发一张新的使用凭据,释放后把该凭据作废;检查后续请求是否仍持有当前凭据。即使槽号重复,也不能把两张不同代次的凭据当成同一个对象。
代次校验只是识别复用对象的一种逻辑,并不是网络身份认证或权限控制。真实系统还可能处理并发、持久化和整数回绕,这些不在本例中。拒绝旧读取不应顺便释放当前新对象,失败操作应保持状态不动。
练习时可以只改动一个输入,再观察哪一步首次出现差异。对等于门槛、重复请求、空集合和最后一步分别留一份记录;如果发现异常,应先回到单位、顺序和边界约定,避免用额外补偿掩盖前面已经发生的错误。
