使用getter或直接访问私有成员是否更好?

时间:2016-12-06 12:38:32

标签: java oop coding-style

以下哪项更好?它是基于意见还是有任何相关的差异?在某些情况下,是否可以选择其中一种?

public class MyClass {
    private Integer myField;

    public void setMyField(Integer myField) {
        this.myField = myField;
    }

    public Integer getMyField() {
        return myField;
    }

}

我需要一种方法来检查是否允许某些东西。请不要谈论这个代码示例的意义。这只是一个很小的例子。

实施1

public boolean isAllowed() {
    MyEnum.ALLOWED.getInt().equals(getMyField());
}

实施2

public boolean isAllowed() {
    MyEnum.ALLOWED.getInt().equals(myField);
}

修改 这篇文章在链接问题中没有答案(见初始帖子的评论)

6 个答案:

答案 0 :(得分:5)

  

以下哪项更好?它甚至是基于意见的还是   有任何相关的差异?可以选择其中一个或另一个   一些场景?

我认为这是良好做法的问题。不同之处在于代码的可读性。

作为一般规则,如果不需要,您应该避免间接。 MyClass的当前实例具有其中一个字段中的信息以实现该操作。它不需要隐藏其内部状态。
因此在内部,MyClass没有任何有价值的理由支持使用getMyField()而不是直接使用myField {1}}字段。
getMyField()访问者更适合该类客户使用 所以我认为在你的示例代码中它总是更好:

public boolean isAllowed() {
    MyEnum.ALLOWED.getInt().equals(myField);
}

修改
除了可读性之外,这里有一个例子,说明为什么你没有兴趣将内部状态耦合到公共吸气剂 假设在开发阶段您从类中删除了public getMyField()方法,因为对于类的客户端不再需要或不需要,如果isAllowed()在其实现中依赖于getMyField(),它将被打破,你应该用myField替换它。

答案 1 :(得分:4)

我的回答不会是最有用的,但它会来自处理这种模式的直接经验。在设计对象时,通常很容易直接访问成员字段而不是依赖访问者。这种愿望源于想要简化对象并避免从简单返回值的方法中添加混乱。将您的示例更进一步添加上下文&意思是:

public class MyClassmate {
    private Integer age;

    public MyClassmate(Integer age) {
        this.age = age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }

}

这里的年龄是一个简单的数字,似乎没有必要在它周围添加getter / setter。如果我们添加以下方法,您将很想直接访问该字段,因为行为没有变化:

public Integer calculateScore() {
    if(age > 21) return 100 - getNumberOfIncorrectAnswers();
    //Add 10% before for younger students
    else return (100 - getNumberOfIncorrectAnswers()) + 10;
}

然后,您的对象可以使用依赖于age字段的方法来增加新功能,您可以继续直接使用它。稍后,您可能会改变年龄的起源方式并从网络中提取价值。您可能不希望在构造函数中包含网络逻辑,因为它是一个昂贵的操作,只应根据需要触发。 calculateScore()方法可以建立网络连接并发现年龄,但是所有其他依赖于年龄的方法也是如此。但是如果calculateScore看起来如下呢?:

public Integer calculateScore() {
    if(getAge() > 21) return 100 - getNumberOfIncorrectAnswers();
    //Add 10% before for younger students
    else return (100 - getNumberOfIncorrectAnswers()) + 10;
}

然后,您可以在不触及calculateScore()方法的情况下增强对象,从而更改其导出年龄的方式。这意味着您的方法遵循开放闭合原则(OCP)。它是开放的增强功能,但已关闭以进行更改,或者您无需更改方法源以更改它的年龄。

根据应用程序和对象模型的复杂程度,封装访问可能仍然有些过度,但即使在这些情况下,理解直接字段访问的权衡也是很好的,这些更简单的方案几乎是罕见的。

一般来说,您应该明白,封装的需求几乎不会立竿见影。随着对象的增长,它随着时间的推移而出现,并且如果对象从一开始就没有设置封装,那么将其逐步进入就更加昂贵。这就是使这种方法难以理解的原因。它需要经验(即,使得典型的过度简化并且在几年内遭受几次痛苦)才能感觉为什么封装是必要的。这不是你可以眼球和发现的东西。

也就是说,这曾经是一个比现在更大的问题,当时IDE并不是全功能的。今天,您可以在某些IDE(如IntelliJ)中使用内置的encapsulate fields重构来根据需要引入模式。即使使用现代IDE,从一开始就实施封装仍然是有利的。

答案 2 :(得分:1)

我建议使用getter,因为在某些情况下,它可以有一些额外的逻辑(如格式化,检查空值等)。因此,在使用字段本身时,您可能会失去一些逻辑。

答案 3 :(得分:0)

为了保持良好的封装,首先想到你需要考虑的是你要在你的课外暴露哪些方法,如果在这里,例如你将只使用被允许的方法,我只会公开方法,并在构造函数中定义字段,如果该字段适合更改,那么您将需要getter / setter但总是取决于您希望从类中提供什么。并保持尽可能多的封装。

public class MyClass {
    private Integer myField;

    MyClass(Integer myField){
        this.myField = myField;
    }

    //Only this method is offered nobody need to know you use myField to say true/false
    public boolean isAllowed() {
        MyEnum.ALLOWED.equals(myField);
    }

}

答案 4 :(得分:-1)

在我的软件工程课程中,我被告知要实现秘密的原则"。因此,您应该始终使用getter和setter例程。这样,您可以确保没有人意外访问成员变量。

奇怪的函数或对象可能永远不会看到甚至更改成员变量,除非您通过setter和getter明确告诉他们这样做。

答案 5 :(得分:-1)

由于您的属性是私有的,因此您只能使用getter或setter方法在其他类中安全地访问它。所以我想说最好的实现是遵循封装原则的实现,即使用getter而不是直接访问的实现。 这也可以防止数据泄漏。

https://www.tutorialspoint.com/java/java_encapsulation.htm