我如何可以避免使用例外流的控制?
-
19-08-2019 - |
题
我已被分配了一个项目,以开发一套课程,作为一个接口,以存储系统。一个要求是,这类支持一个得到的方法与以下特征:
public CustomObject get(String key, Date ifModifiedSince)
基本方法是应该返回 CustomObject
关联 key
如果且只有如果对象已被修改之后 ifModifiedSince
.如果存储系统不包含 key
然后,该方法应该返回null。
我的问题是这个:
我怎么处理这种情况的关键存在,但是对象 不 经修改的?
这是重要的,因为某些应用程序,使用这类网络服务和网络应用程序。这些应用程序将需要知道是否返回404(未找到),304(未经修改),或200(好,这里的数据)。
解决办法,我称是:
- 扔一个自定义的异常时
储存系统没有包含
key
- 扔一个自定义的异常时
ifModifiedSince
失败。 - 增加一个状态的财CustomObject.要求呼叫者检查的财产。
我不乐意与任何这三个选项。我不喜欢选择1和选择2因为我不喜欢使用的异常流量控制。我也不喜欢返回值时,我的意图是要表明,没有 没有价值.
尽管如此,我倾向于选项3。
有一个选项我没考虑吗?没有任何人有强烈的感情有关的任何这三个选择?
对这个问题的答案,解释:
- 提供一个
contains
方法和要求呼叫者叫它 之前的呼叫get(key, ifModifiedSince)
, 扔 异常,如果关键不存在, return null,如果对象没有 修改。 - 包裹的响应和数据(如果有的话) 在一个复合的对象。
- 使用一个预先定义的不断来表示一些国家(
UNMODIFIED, KEY_DOES_NOT_EXIST
). - 呼叫者实现接口 作为回调。
- 设计糟透了。
为什么我不能选择的答案#1
我同意,这是理想的解决方案,但它是一个我已经(无奈地)驳回。这种方法的问题是,在大多数情况下,这些课程将使用后端存储系统将是一个第三方远程系统,如亚马逊S3。这意味着一个 contains
方法将需要往返于储存系统,该系统在大多数情况下将会随后通过另一轮的旅行。因为这个 将花费时间和金钱, 它不是一个选项。
如果不是因为,限制,这将是最好的办法。
(我意识到我没有提到这一重要元素在的问题,但我试图保持它的简短。显然,这是相关的。)
结论:
后读取所有的答案,我们得出的结论是,一个包装是最好的办法在这种情况。基本上我就模仿HTTP,用元数据(标题)包括一个响应的代码和内容体(消息)。
解决方案
这听起来像你真的想要返回的两个项目:响应的代码和目的发现。你可以考虑创建一个轻型包装,保持两者并返回他们在一起。
public class Pair<K,V>{
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.
}
Ok,你不是送302在这种情况下,但也许这就是它的方式设计。
我的意思是,出于安全原因,服务器不应返回的更多信息,比, [探测是得到(键,日期)才回null或对象]
所以不要担心它。谈谈你的经理,并让他知道这一决定。评论的代码这一决定。如果你有建筑师在一方面确认背后的理由这个奇怪的限制。
机会是他们你没有看到这来了,他们可以修改合同之后,你建议。
有时候,同时要继续执行正确的,我们可以继续进行错误和妥协的安全的我们的应用程序。
与你的团队。
你可以创建一个特殊的最终CustomObject作为一个"标记",以表明不变:
static public final CustomObject UNCHANGED=new CustomObject();
和测试用于一个匹配"=="代替。等().
它还可能作为回null上不变,并把一个异常上不存在?如果我必须选择你的3个,我会选择1,因为这似乎是最特殊的情况。
寻找一个对象不存在似乎是一个特殊的情况下给我。耦合的方法,允许一个呼叫者来确定,如果对象是存在的,我认为这将是确定以扔的例外时,它不。
public bool exists( String key ) { ... }
呼叫者可以这样做:
if (exists(key)) {
CustomObject modified = get(key,DateTime.Today.AddDays(-1));
if (modified != null) { ... }
}
or
try {
CustomObject modified = get(key,DateTime.Today.AddDays(-1));
}
catch (NotFoundException) { ... }
该问题与例外情况是他们都是信号的一个"快速失败"的情况(即如果不处理,一个例外 停止 应用程序)由于一个特殊的 和异常 行为。
我不认为"该方案的关键存在,但是目的未经修改"是一个例外,当然不是一个异常之一。
因此,我将不使用例外,而是我会文件的行动的呼叫者的需要做,以便正确地解释本结果(财产或特殊对象)。
如何严格的要求,方法的签名吗?
它看起来好像你正在一个项目,该项目仍在进行中。如果消费者的类是其他开发的,你可以说服他们的方法,签署他们已要求是不够?也许他们还没有意识到,应该有两个独特的故障模式(项不存在和对象未经修改)。
我将讨论它,与你的主管,如果这是一个选项。
我还是返回null。
打算在财产是返回的对象,这是修改后的指定的日期。如果返回null为对象不是确定的,那么肯定回null为未经修改的目的是确定。
我个人将返回的null非修改的对象,并把一个异常用于非现有的对象。这似乎更加自然。
你说的很对不使用例外流量控制顺便说一句,所以如果你只有3个选择,你的直觉是正确的。
你可以遵循。净库模式并有一个公共静只读场中的定义称为对象 CustomObject.空 的类型 CustomObject (像串。空和Guid。空)。你可以返回这个如果目的不是修改(功能的消费者将需要比较)。
编辑: 我只是刚刚发现你的工作,但原则上仍然适用
这让你有选择的以下
Return null if的关键并不存在。
返回 CustomObject.空 如果关键的存在,但是对象尚未被修改。
其缺点是,消费者需要知道之间的差空返回值和CustomObject.空返回值。
也许是酒店会更恰当地称为 CustomObject.NotModified 作为空是真正用于的价值类,因为他们不能为空。还 NotModified 会传达的意义的领域更容易地到消费者。
在(目的)的接口有关的要求,严重破坏。你尝试去做不相关的事情一方法。这是走向软件的地狱。
提供回调作为参数,其中的回流可能是事件驱动的,或器驱动的。
你有你的类的接口定义的各种可能发生的错误的,通过在CustomObject作的参数为事件,如果需要的话。
public interface Callback {
public void keyDoesNotExist();
public void notModified(CustomObject c);
public void isNewlyModified(CustomObject c);
.
.
.
}
在这种方式,允许实施者的回调界定什么时候做的事件发生,而且你可以选择通过该接口,否,条件要求传递的检索到的对象。最后,它可降低复杂性的逻辑上的回报。您的方法不止一次。实现API不需要这样做,因为它的完成。
如果它是可以接受的,你可以回放大CustomObject(a wrapper),其中载有价值所表示的对象及其修改国家,如果有的话,等等。