在setter方法中使用trim是一个好的实践吗?

8

我正在进行代码审查,发现了这样的代码:

@Entity
@Table(name = "SOME_TABLE")
public class SomeReportClass {

@Column(name = "REPORT_NUMBER", length = 6, nullable = false)
private String reportNumber;

.....
    public String getReportNumber() {
        return reportNumber;
    }

    public void setReportNumber(String reportNumber) {
        this.reportNumber = StringUtils.trimToNull(reportNumber);
    }

每次我看到在setter方法内部进行截取时,都觉得这不是最清晰的解决方案 - 针对这个问题通常的做法是什么?


2
就个人而言,我并不认为这里有任何问题(即使我自己的代码也是这样)。基本上使用getter/setter来放置有效和干净的数据(除了封装)是没有问题的。因此,我认为这不应该是一种不好的做法。 - Pradeep Simha
我完全没有看到这段代码有任何问题,只要文档正确描述了行为,这比每次设置之前都修剪字符串要好得多。 - LionC
4个回答

3

如果您知道您总是需要修剪值,那么此方案将避免代码重复,即在设置之前,您必须始终修剪并担心哪里错过了修剪。我认为,在setter中具有这个功能是一个好的实践。


你说的“自定义的用户类型自动应用会更好”是什么意思? - Arsen Alexanyan
这个问题是关于“对还是错”的。在这里定义自定义的UserType没有意义,因为您必须再次在setter方法中重用它。 - Arsen Alexanyan

2
使用setter方法来执行除透明设置值之外的任何操作都违反了“关注点分离”原则:通过这种设计,您已经永久地将“设置”关注点与“修剪”关注点交织在一起。只要您确信在程序的生命周期内,永远不会有一个用例需要进行设置而不是修剪,那么这很好。一旦您需要它,这种设计的失败模式就相当可悲:您将拥有一个常规的set方法,实际上是“特殊”的,并被迫添加另一个setWithoutTrimming方法,完全与新程序员的任何理智假设相反。
更一般地说,我的选择是使用纯公共字段(Hibernate支持它们,以及Spring,Jackson等),这使得设置它们的语义非常清晰。如果我有另一个关注点,例如修剪,则使用对一个静态方法(一个纯函数)的显式调用来执行必要的转换。这导致了明确和明显的设计,没有任何WAT(例如,“为什么getter返回的值与我刚刚设置的不同?”)。

为什么getter返回的值与我刚设置的不同?如果setter有良好的文档记录,你就会知道期望得到什么值。 - JamesB
我同意第一部分,但不同意第二部分。拥有“private”字段可以在不修改公共API的情况下更改内部结构。例如,曾经是“int”的东西现在应该是一个“String”,以允许前缀。使用重载的setter将允许向后兼容,而暴露内部则不会(除非使用hack)。 - Ingo Bürk
2
@IngoBürk 是的,有一些特殊情况可以证明访问器是合理的——只是,在我15年的商业软件专业经验中,我还没有遇到过这样的情况。请注意,我们在这里讨论的是数据库实体,而不仅仅是一些随意的Java对象。如果我设计一个公共API,我绝对不会使用公共字段。 - Marko Topolnik
1
这只是公共API的问题。我完全同意保持setter的清洁,否则你会建立一个陷阱,很容易找到,但每个使用这段代码的开发人员都会遇到它至少一次,这非常令人恼火。 - Ingo Bürk
@IngoBürk 就像这个网站上第10,001个关于“为什么我的字符串比较结果为false?”的问题一样让人烦恼 :) - Marko Topolnik
显示剩余2条评论

0

我认为只要方法有清晰的文档说明,其中的逻辑就没问题。

归根结底,你不想在代码中出现大量在调用setter之前执行修剪操作的地方。

如果您后来决定不再需要修剪字符串,则只需进行一次更改。

毕竟,封装的目的是将数据和行为放在同一个地方。


如果他后来决定有一个特殊情况不想要修剪怎么办?这就是为什么在我看来这是个坏主意。 - Marko Topolnik
@MarkoTopolnik 为特殊情况添加另一个setter? - JamesB
然后你的设计被颠倒了:原本应该是基本情况的现在变成了专门的setter,而普通的setter实际上是特殊的。 - Marko Topolnik

0

这段代码没问题。使用setter比公共值更好的原因是,你可以在其中引入任何逻辑而不会破坏类的接口。我只有一个注意事项,如果你在setter中修剪字符串,则应始终在getter中修剪它。在你当前的情况下,你会遇到一个问题:

  1. 获取任何空白值
  2. 将其设置回去
  3. 然后再次尝试获取

第一次和最后一次获取将不同。如果表格可以从外部实体填充,则可能会出现这种情况。


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