我的getter方法改变存储的值是不好的实践吗?

72

把我的getter方法改成类中的版本2,这是一个不好的实践吗?

版本1:

 public String getMyValue(){
     return this.myValue
 }

版本2:

 public String getMyValue(){

    if(this.myValue == null || this.myValue.isEmpty()){
       this.myValue = "N/A";
    }

    return this.myValue;
 }

5
在我看来,如果这种副作用在文档中有明确的记录,那么这是可以接受的。 - jlordo
我认为这不是一个主要问题。这很好,但在方法之前必须提供清晰的Java文档。 - The Dark Knight
3
我认为这不好,因为似乎你把演示和数据模型混在一起了。如果你的应用程序需要翻译成其他语言,会发生什么? - MTilsted
8
我不喜欢你的更改,但总体上我认为更改getter是可以接受的。毕竟,getter是一种抽象,可以在不破坏其他代码的情况下使我们能够更改内部行为。 - Matsemann
2
问题标题不应该是“获取器更改对象成员的值是否是一种不好的做法?”,这样听起来像是在问获取器内部实现更改是否不好,而我认为答案是否定的,更改是可以的。 - vikki
显示剩余5条评论
14个回答

120

我认为如果你的getter方法改变了对象的内部状态,那么这实际上是一个相当糟糕的做法。

为了达到相同的效果,我建议只需返回"N/A"

  • 一般来说,这个内部字段可能会在其他地方(内部)使用,而您不需要使用getter方法。因此,在最终情况下,调用foo.getMyValue()可能会实际上改变foo的行为。

或者,可以在setter中将null转换为"N/A",即如果传递null,则可以将内部值设置为"N/A"


一般的备注:
我只会添加类似于"N/A"的状态,如果它们被某些API或其他依赖于您的代码的实例所期望。如果不是这种情况,您应该依赖于编程语言中可用的标准null类型。


45
注意:我认为在延迟加载的情况下,getter方法可以改变对象的内部状态,因为您只想在调用getter方法时加载数据。 - Vincent Mimoun-Prat
5
好的,这是一个有效的使用案例。但是,OP描述的情况可能会导致可怕的副作用。 - fgysin
4
处理一个在getter上改变状态的属性,并且每当调试器的某个组件访问它时,状态都会改变,这是非常烦人的事情。 - Chuu
6
我认为在getter中更改对象的内部状态没有任何问题。对象的内部状态是类作者的事情,作为类的使用者,只要外部接口一致,你不需要知道(或关心)内部发生了什么。因此,无论他是在setter中设置值还是在getter中懒惰地设置值,这都是完全有效的。重要的是getter始终对空值或空字符串返回N/A。 - laurent
1
同意@Laurent的观点,这只是实例变量的懒加载,是非常常见的做法。不确定是否要检查.isEmpty(),甚至使用“N/A”作为默认值(我可能更喜欢使用Null Object或异常,因为默认情况下的值/处理通常取决于调用方,而不仅仅是被调用对象)。 - Damien Pollet
显示剩余3条评论

38

我认为,除非你正在进行lazy-loading(在这种情况下你没有这样做),否则getter不应该改变值。所以我会选择:

将更改放在setter中。

public void setMyValue(String value) {
    if(value == null || value.isEmpty()){
        this.myValue = "N/A";
    } else {
        this.myValue = value;
    }
}

如果值没有被正确设置,可以使 getter 返回默认值:

public String getMyValue() {
    if(this.myvalue == null || this.myvalue.isEmpty()){
        return "N/A";
    }    
    return this.myValue;
}

在懒加载的情况下,我认为在getter中更改成员是可以的,你可以这样做:

在懒加载的情况下,我认为在getter中更改成员是可以的,你可以这样做:

public String getMyValue() {
    if (this.myvalue == null) {
        this.myvalue = loadMyValue();
    }    
    return this.myValue;
}

为什么要把你的惰性加载方法命名为get...()呢?像load...()这样的名称似乎更合适,不是吗? - Lucas Hoepner
1
因为getter直接返回值,除非它以前从未被加载过(因此在getter内部调用loadMyValue)。调用getter loadMyValue将意味着(根据我的理解)它无论如何都会加载该值。 - Vincent Mimoun-Prat

12

不是的。你在这里做了两件事情。获取和设置。


我实际上更喜欢被接受的答案。它指出,你可以返回值“N/A”而不是首先更改类变量。 - Mark W

11

是的。这是一种不好的做法。

为什么?

当值被设置时(在构造函数或setter方法中),应该进行验证,而不是在调用getter方法时进行验证。创建一个privatevalidate*方法也是一个好主意。

private boolean validateThisValue(String a) {
     return this.myValue != null && !this.myValue.isEmpty();
}

public void setThisValue(String a) {
    if (validateThisValue(a)) {
        this.myValue = a;
    } 
    else {
        // do something else
        // in this example will be
        this.myValue = "N/A";
    }
}

在 getter 方法中,绝对不要更改对象的状态。我曾经参与过一些项目,在其中 getter 经常必须被设置为 const: "该方法不能更改内部状态"。

至少,如果你不想把事情变得复杂,在 getter 方法中,你应该返回"N/A"而不是更改内部状态并将myValue设为"N/A"


4
我不同意在setter中永远不改变值。使用getter/setter的整个目的是为了抽象内部和外部实现。 Person.setHeightInCentimeters(int value)Person.setHeightInMeters(double value)Person.setHeightInFeetAndInches(int feet, int inches) 应该共享单个内部表示,这意味着其中至少两个将存储除输入值之外的内容。 - Dan Is Fiddling By Firelight
啊,非常抱歉 :( 我犯了类型不匹配的错误,在getter中没有做任何更改。正如你在我的代码中看到的那样,我已经更改了setter的内部状态。我已经进行了编辑。非常抱歉。 - hqt

6

我通常定义一个特定的getter

不要更改原始的getter

 public String getMyValue(){
     return this.myValue
 }

并创建一个特定的getter

public String getMyValueFormatted(){

    if(this.myvalue == null || this.myvalue.isEmpty()){
       return "N/A";
    }else{
       return this.myValue;
    }
 }

你如何知道什么时候该调用哪个函数? - Abhishek Mehta
第二个方法的意图是为了向用户展示。 - Rodrigo
那么第一个应该不是公共的? - Abhishek Mehta
不需要。两个都是公共的。使用第一个来获取原始值。当需要格式化值时,使用第二个。简单明了,不需要复杂的getter/setter方法。 - Rodrigo
1
对于调用API的新开发人员来说,这可能会令人困惑。第一种方法:将第一个公共方法重命名为getMyValueOriginal,将第二个方法重命名为getMyValueFormatted。 - Abhishek Mehta

5
我认为最好初始化 this.myValue = "N/A"。并且后续对setMyValue的调用应根据您的业务条件修改this.myValue
getMyValue不应以任何方式修改this.myValue。如果您需要返回某个值,应该返回该值(如“N/A”),而不是更改this.myValue。Getter不能修改成员变量的值。

4
我会更改setter方法,如果值为null或空,则将N/A分配给属性。因此,如果在类内的其他方法中使用该属性(例如toString()),则会在那里获得预期值。
或者,更改setter方法以在设置的值不正确时抛出异常,以便程序员在设置值之前被迫改进其处理方式。
除此之外,一切都好。

4

我认为这是一种不好的做法,除非你能够解释为什么在getter方法内修改对象是必要的,而不是在setter方法中进行修改。
你认为有些原因阻止了这样做吗?请您详细说明。


4

无论何时,访问器和设置器只是另一种公共方法。您可以使用任何其他名称。

但是,如果您使用像Spring这样的框架,您必须使用这些标准名称,而且不应该在其中放置自定义代码。


4

毫无疑问,这是一种不良做法。

想象一下,你通过网络与第三方进行通信(远程调用、COM等),这将增加往返时间,进而影响应用程序性能。


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