我应该在Java中的库API中添加帮助/实用程序方法吗?

时间:2017-07-31 13:03:49

标签: java api-design

我正在开发一个Java小库,它可以从压缩的图像数据源(例如PNG文件)中读取图像并对其进行解码,返回Image个对象。 Image类具有名为Image.createImage(...)的各种函数,可以根据指定的参数创建图像。

我已经向库API添加了几个公共Image.createImage(...)方法,每种方法对应一种数据源类型:Image.createImage(Path)Image.createImage(InputStream)Image.createImage(String)Image.createImage(byte[]) ,...,让用户轻松从各种数据源获取Image,而无需输入大量代码。

然而,这意味着每个方法都重复使用Javadoc并且API变得更大,所以有点难以学习,即使辅助方法本身非常简单(例如Image.createImage(byte[])只是return Image.createImage(new ByteArrayInputStream(array));) ,所以我决定重新设计我的库API设计。

我想到了三种不同的方法来重新设计我的Image API:

  • 仅提供采用输入流的单个图像解码方法,例如, Image.createImage(InputStream),让用户自己从他的数据源创建一个输入流(也许包括Javadoc中的一些示例代码,例如“解码存储在文件中的图像,你可以使用Files.newInputStream(Paths.get(...))。 ..“)
  • 为每种数据源类型提供(辅助)方法,例如Image.createImage(ByteBuffer)Image.createImage(Path),...每个方法都重复使用Javadoc (这实际上是当前情况)
  • 设计一个DataSource类,可以从其中一种数据源类型构建(例如new DataSource(Path),...),并使用单个图像解码方法获取DataSource对象,例如Image.createImage(DataSource)

我想知道哪种设计是最好的设计。

  • 我认为第一个非常好,因为它使库非常小/轻,但缺点是用户必须自己编写“粘合代码”(或者从Javadoc示例中复制它),因此必须知道如何从Path或资源字符串中获取InputStream。我很想选择这种设计。
  • 我认为第二个不太好,因为Javadoc变得非常“冗长”/大而且可能不值得为API添加单行方法。
  • 我认为第三个可能是最糟糕的一个,因为如果用户必须阅读Image和{{1}的Javadoc,那么用户获得Image会变得太复杂然后找到如何创建一个DataSource,我个人也发现它非常“重量级”-ish(让我想起非常大的框架,包含大量的类和包,而我喜欢让我的项目保持小简洁)。

如果您要使用此库,您更喜欢哪种设计?第一个设计是最好的吗?

5 个答案:

答案 0 :(得分:3)

约书亚布洛赫说,

  

API应尽可能小但不小“

     

•如有疑问,请将其删除──功能,类别,方法,   参数等──您可以随时添加,但永远不能删除

从这个链接看第14页

http://www.cs.bc.edu/~muller/teaching/cs102/s06/lib/pdf/api-design

答案 1 :(得分:3)

你的实际设计似乎很好。

  

为每种数据源类型提供(辅助)方法,例如   Image.createImage(ByteBuffer),Image.createImage(Path),... with   每个方法都重复使用Javadoc(这实际上是   现状)

更多的API使用起来更简单,更好 提供方法重载通常是一个优点,因为客户端不需要记住很多东西来应用处理/创建具有不同风格的对象。
他/她必须只记住the方法。

查看java.io包中的JDK类:FileInputStreamFileOutputStream
这些是以这种方式设计的:

  

public FileInputStream(String name)抛出FileNotFoundException {

     

public FileInputStream(File file)抛出FileNotFoundException {

     

public FileInputStream(FileDescriptor fdObj){

当然,如果您定义了许多重载方法,例如8个或更多,则情况会有所不同 您的API可能变得更难阅读,使用并且可能容易出错 对你来说似乎不是这样。

使用javadoc来记录每种方法应该不是问题 客户不必刻意学习。

此外,它们的javadoc应该非常相似:

  • Image.createImage(Path)
  • Image.createImage(InputStream)
  • Image.createImage(String), -
  • Image.createImage(byte[])

这些方法的javadoc可能总是引用@see{@link} javadoc注释的常用方法。

最后,由于每种方法都使用不同的类型作为参数,我们可以轻松猜出。

之间的差异

答案 2 :(得分:3)

你已经得到了很好的答案,但是关于javadoc:只需使用链接到其他方法,使用:

{@link package.class#member label}

含义:如果你真的有一组相关的方法做“相同”需要不同的参数 - 那么不仅避免代码重复,而且避免文档重复是一种好的做法。所以:

/**
 * This is the extensively documented "anchor" method ...
 * @param String path to image as String ...
 */
public void createImage(String path) { ...

/** 
 * See {@link ...
 * and some additional information ...

答案 3 :(得分:1)

从设计的角度来看,它实际上取决于您对图书馆的目标是什么以及您想要扩展它的距离。

  • 第一个选项创建了一个非常轻量级的库,可以在多种场合使用,但是向用户提供了许多你知道需要完成的工作,还有一些你并不知道的工作。它很容易编写,并没有限制你使用它的方式,但它不是那么容易使用,如果你只是想要使用大量的代码,它可能真的不值得

  • 如果你保持原样,你将保持一个巨大的(从外面)库非常容易使用。但是,正如其他人提到的那样,可能难以保留。

  • 在我看来,第三种情况是面向对象的。您抽象出DataSource的概念,您基本上可以创建类的层次结构,每种类型的源都需要一个。易于扩展,易于使用(采用适当的工厂方法)。要创建一个可维护的库,我会使用这种方法。

另一方面,如果你唯一担心的是重复JavaDoc描述,你可以随时使用{@link} tag to write it once and refer it everywhere else

答案 4 :(得分:-1)

问题似乎与创建有关。考虑支持多个数据源的Image。胶水代码在工厂中,因此只有一个Image构造函数。

也许将npm install ngx-bootstrap bootstrap-sass 的构造函数设为私有,以便用户需要使用工厂。