我被分配了一个项目来开发一组作为存储系统接口的类.要求是该类支持具有以下签名的get方法:
public CustomObject get(String key, Date ifModifiedSince)
基本上该方法应该返回CustomObject
与key
if 关联的,并且只有在对象被修改之后才会返回ifModifiedSince
.如果存储系统不包含,key
则该方法应返回null.
我的问题是:
如何处理其中关键的存在,但该对象的情景已经不被修改?
这很重要,因为使用此类的一些应用程序将是Web服务和Web应用程序.这些应用程序需要知道是返回404(未找到),304(未修改)还是200(OK,这是数据).
我正在权衡的解决方案是:
当存储系统不包含时,抛出自定义异常
key
ifModifiedSince
失败时抛出自定义异常
.
将状态属性添加到CustomObject.要求来电者查看房产.
我对这三个选项中的任何一个都不满意.我不喜欢选项1和2,因为我不喜欢使用流控制的异常.当我的目的是表明没有价值时,我也不喜欢返回值.
尽管如此,我倾向于选择3.
有没有我不考虑的选择?有没有人对这三种选择中的任何一种都有强烈的感受?
这个问题的答案,转述:
提供一个contains
方法并要求调用者在调用之前调用它get(key,
ifModifiedSince)
,如果key不存在则抛出异常,如果没有修改object则返回null.
将响应和数据(如果有)包装在复合对象中.
使用预定义常量表示某个state(UNMODIFIED, KEY_DOES_NOT_EXIST
).
调用者实现了用作回调的接口.
设计很糟糕.
为什么我不能选择答案#1
我同意这是理想的解决方案,但我已经(不情愿地)被解雇了.这种方法的问题在于,在大多数使用这些类的情况下,后端存储系统将是第三方远程系统,如Amazon S3.这意味着一种contains
方法需要往返于存储系统,这在大多数情况下会进行另一次往返.因为这会花费时间和金钱,所以不是一种选择.
如果没有这个限制,这将是最好的方法.
(我意识到我没有在这个问题中提到这个重要元素,但我试图保持简短.显然它是相关的.)
结论:
在阅读完所有答案之后,我得出的结论是,在这种情况下,包装器是最好的方法.基本上我会模仿HTTP,包括响应代码和内容正文(消息)的元数据(标题).
听起来你实际上想要返回两个项目:响应代码和找到的对象.您可以考虑创建一个包含两者并将它们一起返回的轻量级包装器.
public class Pair{ public K first; public V second; }
然后,您可以创建一个包含响应代码和数据的新对.作为使用泛型的副作用,您可以将此包装重用于您实际需要的任何对.
此外,如果数据尚未过期,您仍然可以返回它,但是给它一个303代码,让他们知道它没有变化.4xx系列将配对null
.
根据给定的要求,您无法执行此操作.
如果您设计了合同,则添加条件并调用调用者
exists(key): bool
服务实现如下所示:
if (exists(key)) { CustomObject o = get(key, ifModifiedSince); if (o == null) { setResponseCode(302); } else { setResponseCode(200); push(o); } } else { setResponseCode(400); }
客户端保持不变,从未注意到您已经预先验证过.
如果你没有设计合同可能有一个很好的理由,或者可能只是设计师(或建筑师)的错误.但既然你无法改变它,那么你也不必担心.
那么你应该遵守规范并继续这样:
CustomObject o = get(key, ifModifiedSince); if (o != null) { setResponseCode(200); push(o); } else { setResponseCode(404); // either not found or not modified. }
好的,在这种情况下你不会发送302,但可能就是它的设计方式.
我的意思是,出于安全原因,服务器不应该返回更多信息[探测器获取(键,日期)只返回null或object]
所以不要担心.与您的经理交谈,让他知道这个决定.用这个决定评论代码.如果你有建筑师在手,确认这个奇怪的限制背后的理由.
你可能没有看到这一点,他们可以根据你的建议修改合同.
有时候,如果想要正确行事,我们可能会出错并损害我们应用的安全性.
与您的团队沟通.