缩小或扩大类型?我的公共API应该返回什么?

3
最近我和朋友讨论了创建公共API的良好实践,当我们谈及返回类型时开始产生争论。他告诉我只返回广义类型,例如List而不是ArrayList。但是在我看来这完全取决于我们要解决的问题。我认为以下代码没有任何问题:
ArrayList foo();
当我想要表达“嘿,我给你一个ArrayList,只是为了确保你能在O(1)时间内访问到元素”。
在下一个例子中,假设方法签名或文档中没有关于返回的图的种类或表示形式的信息。
Graph foo();
现在怎么办?我可能会想知道这个图是有向还是无向的,基于邻接列表还是邻接矩阵。最糟糕的是,它可能会导致像这样的代码:
Graph graph = foo();
if(graph instanceof DirectedGraph)
//code

这违反了Liskov替换原则。

你有什么想法?

4个回答

2
思考一下为什么要公开API,以及为什么有人会使用它?最显而易见的原因是将问题(和解决方案)的复杂性隐藏在API用户之外。API用户不想关心实现细节和底层复杂性,这些本来就被你抽象出来了。
作为API提供者,通常情况下,你不想限制自己只使用具体的实现,比如这个例子中的ArrayList。即使大多数时候应该使用ArrayList作为List接口的实现,也有可能陷入LinkedList表现更好的情况。这将破坏你现有的API,客户端显然必须重新实现这个变化。这正是你不想做的事情。
看看编程到接口的概念。
你能否在同一个接口中放置有向图和图形取决于你的使用情况。但是,你肯定可以提供两个接口,一个用于图形,另一个用于有向图形,以保护API用户免受这些图形实现未来更改的影响。
API用户应该能够指定他想要的图形类型,有向或非有向,并且你应该能够隐藏具体的图形实现细节。

很好的简明回答。我想补充一点,_有时候_在这种情况下Java泛型是很好的选择(但显然取决于领域/上下文)。 - WIlfinity

0

I see nothing wrong in:

ArrayList foo();

When I want to say "Hey I am giving You ArrayList just to assure that u got access to elements in O(1) time"

当返回ArrayList时,您所表达的不仅仅是它。您所表达的是:此方法返回列表的一个非常特定的实现:ArrayList,所有对此方法的覆盖也必须返回此非常特定的实现,而不是其他任何东西。
还有一些其他的List实现是O(1)的,但它们不是ArrayList:
- 由Arrays.asList()返回的列表 - CopyOnWriteArrayList - 由Collections.emptyList()或Collections.singletonList()返回的列表 - 任何O(1)列表包装到Collections.synchronizedList()或Collections.unmodifiableList()中的列表 - ...
这会限制您以及子类(如果类设计用于子类化),从而使您的代码难以演进。而且对于调用者来说并没有太多好处:文档可以说明列表是RandomAccess,如果他真的想让非随机存取列表成为RandomAccess,调用者可以复制它。
关于您的第二个例子,如果Graphs的类型具有相同的Graph接口,则调用者不需要关心返回哪个具体实现。
因此,规则可以是:返回您现在和未来以及所有可能的子类可以保证的最精确的接口。但是,在接口类型可以使用时,请避免返回具体实现类型。
当然,这实际上取决于您拥有的类型、它们的设计和用例。设计更像是一门艺术而不是科学。

0
当我想说“嘿,我给你ArrayList只是为了确保你可以在O(1)时间内访问元素”时,听起来像是过早优化。
Graph foo();
图形始终是隐式无向的。有向图是有向的。如果没有明确区分无向图和有向图,那么将有向图称为图形是滥用术语--在这种情况下,我会将IGraph作为接口,然后使Digraph和Graph实现该接口。
从使用图形作为数据类型(没有行为)的角度来看,我认为使用有向图作为图形没有问题--它将简单地忽略其元素(边缘和顶点)的顺序。但是,使用图形作为有向图可能会有问题,因为元素的顺序可能是随机的(应该将其元素存储在bag中)。也就是说,您不能确定元素总是以相同的顺序返回,这不会使它们的顺序恒定。

0
当我想说“嘿,我给你ArrayList只是为了确保你可以在O(1)时间内访问元素”时,
你必须在接口中仅暴露所需的内容,既不多也不少。因此,在需要保证O(1)访问时使用ArrayList是正确的,你的实现不太可能因此而改变。
Graph foo()的实现告诉你两种类型的图形都可以返回,所以你可以根据需要进行强制转换或检查。
不要过早优化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接