流利的接口 (最初由Martin Fowler 创造)是一种非常方便的与OOP中的对象进行通信的方式。 它使他们的外墙更易于使用和理解。 但是,它破坏了它们的内部设计,使它们更难以维护。 Marco Pivetta在他的博客文章Fluent Interfaces is Evil中说了几句话; 现在我加几分钱。
让我们看一下我自己的库jcabi-http ,它是几年前创建的,当时我认为流畅的接口是一件好事。 这是您使用库发出HTTP请求并验证其输出的方式:
String html = new JdkRequest("https://www.google.com").method("GET").fetch().as(RestResponse.class).assertStatus(200).body();
这种便捷的方法链接使代码简短明了,对吧? 是的,表面上确实如此。 但是,包括JdkRequest
在内的库类的内部设计远非优雅。 最大的问题是它们很大,而且 无法扩展它们而不扩大它们。
难
例如,现在JdkRequest
具有方法method()
, fetch()
和其他一些方法。 需要新功能时会发生什么? 添加它的唯一方法是通过添加新方法来扩大类的范围,这是我们危害其可维护性的方式。 例如, 在这里 ,我们添加了multipartBody()
, 在这里我们添加了timeout() 。
在jcabi-http中收到新功能请求时,我总是感到害怕。 我了解这很可能意味着向Request
, Response
和其他已经膨胀的接口和类添加新方法。
我实际上试图在库中做一些事情来解决这个问题,但这并不容易。 查看此.as(RestResponse.class)
方法调用。 它所做的是用RestResponse
装饰一个Response
,以便使其方法更丰富。 我只是不想让Response
包含50多种方法,就像许多其他库一样。 这是它的作用(这是伪代码):
class Response {RestResponse as() {return new RestResponse(this);}// Seven methods
}
class RestResponse implements Response {private final Response origin;// Original seven methods from Response// Additional 14 methods
}
如您所见,我没有将所有可能的方法添加到Response
,而是将它们放置在补充修饰符RestResponse
, JsonResponse
, XmlResponse
等中 。 它有帮助,但是要使用Response
类型的中心对象编写这些装饰器,我们必须使用“ ugly”方法as()
,该方法as()
很大程度上依赖于Reflection和类型转换 。
流利的接口意味着大型类或某些丑陋的解决方法。
换句话说,流畅的界面意味着大型类或一些丑陋的解决方法。 当我写有关Streams API和接口Stream的文章时 ,我曾提到过这个问题,它非常流畅。 有43种方法!
这是流畅接口的最大问题-它们迫使对象变得巨大。
流利的接口非常适合其用户,因为所有方法都在一个地方,并且类的数量非常少。 使用它们很容易,尤其是在大多数IDE中使用代码自动完成功能时。 它们也使客户端代码更具可读性,因为“流利的”结构看起来类似于纯英语(aka DSL )。
没错! 但是,它们对对象设计造成的损害是价格过高。
有什么选择?
我建议您改为使用装饰器和智能对象 。 如果现在可以做的话,这就是我设计jcabi-http的方法:
String html = new BodyOfResponse(new ResponseAssertStatus(new RequestWithMethod(new JdkRequest("https://www.google.com"),"GET"),200)
).toString();
这与上面的第一个代码段中的代码相同,但是它更加面向对象。 当然,此代码的明显问题是IDE无法自动完成几乎所有操作。 同样,我们将不得不记住许多类的名称。 对于那些习惯了流利界面的人来说,该结构看起来很难阅读。 此外,它与DSL的想法相距甚远。
流畅的界面对用户有利,但对开发人员不利。 小对象对开发人员有好处,但难以使用。
但是,这里是好处列表。 首先,每个对象都很小,非常有凝聚力,并且它们都是松散耦合的,这在OOP中是显而易见的优点。 其次,向库中添加新功能就像创建新类一样容易。 无需接触现有课程。 第三,由于类很小,因此简化了单元测试。 第四,所有类都是不可变的,这在OOP中也很明显 。
因此,有用性和可维护性之间似乎存在冲突。 流利的接口对用户有利,但对库开发人员则不利。 小对象对开发人员有好处,但难以理解和使用。
似乎是这样,但前提是您已经习惯于大型类和过程编程。 对我来说,大量的小班学习似乎是一种优势 ,而不是缺点。 即使我不确定确切的类最适合我,内部清晰,简单且易读的库也更易于使用。 即使没有代码自动完成功能,我也可以自己解决,因为代码很干净。
另外,我经常发现自己对在代码库内部或通过对库的拉取请求扩展现有功能感兴趣。 如果我知道所引入的更改是孤立的并且易于测试,那么我对此更感兴趣 。
因此,我再也没有流畅的界面,只有对象和装饰器。
翻译自: https://www.javacodegeeks.com/2018/03/fluent-interfaces-are-bad-for-maintainability.html