私有列表与Getter/Setter方法相比公共列表的优缺点

3

在类中,将全局列表设为私有并使用getter和setter方法是否比将其设为公共的更好?在Java中的标准是什么?

我曾经学过将变量设为私有,并只提供getter和setter方法,但访问公共列表肯定比访问私有列表更好看。

public exampleclassThatContainsTheList.goodieList.add("Candy");

private exampleclassThatContainsTheList.setGoodieList(exampleclassThatContainsTheList.getGoodieList().add("Candy"));

那是我的观点,但当然我更愿意按照标准而不是外表来进行。


1
为什么不创建一个名为add()的方法,将对象“Candy”添加到列表中呢? classThatContainsTheList.add(“Candy”); - AntonH
2
虽然不是铁律,但“迪米特法则”在这些情况下提供了一些好的建议。 - Mark Peters
这被称为封装。好处很多,但通常都属于抽象的范畴。您可以更改get方法的操作而不会破坏依赖类。使用直接成员访问无法做到这一点。 - Boris the Spider
1
@dalawh 你可以添加需要的功能方法。如果只需要添加和删除,那就只写这些方法。这些方法会按照经典方式操作列表。我不是说这是最好的方法,但这是一个值得考虑的可能性。 - AntonH
@BoristheSpider 我知道这一点,但我不打算添加额外的功能。回到你的陈述;你建议我将它设为私有的吗? - dalawh
显示剩余5条评论
4个回答

2
首先,除非它们是常量(static final)字段并且确保它们的状态不会改变,否则不应直接使用public字段。应该使用封装来公开它们,以避免类的客户端修改它们的状态。以下是一个示例,当通过实现具有防御性的getter/setter来编写自己的框架时,以便不改变您的List的当前状态:
public class Foo {
    private List<String> stringList;
    public Foo() {
        //always initialized, never null
        this.stringList = new ArrayList<>();
    }
    public List<String> getStringList() {
        //defensive implementation
        //do not let clients to alter the state of the list
        //for example, avoiding clear the list through getStringList().clear()
        return new ArrayList(stringList);
    }
    public void setStringList(List<String> stringList) {
        //defensive implementation
        //do not let clients to pass a null parameter
        this.stringList = (stringList == null) ? new ArrayList<>() : new ArrayList<>(stringList);
    }
}

除此之外,JavaBean规范 还指出,Java类中的字段不应该是public的,它们的访问应该通过getter和setter方法进行。
“7个属性” 属性是Java Bean的离散命名属性,可以影响其外观或行为。例如,GUI按钮可能具有名为“Label”的属性,该属性表示按钮中显示的文本。 属性以多种方式出现: 1. 属性可以在脚本环境中公开,就好像它们是对象的字段一样。因此,在Javascript环境中,我可能会执行“b.Label = foo”来设置属性的值。 2. 其他组件可以通过调用它们的getter和setter方法(参见下面的第7.1节)来编程访问属性。
(...)
“7.1 访问器方法” 属性始终通过其所属对象上的方法调用进行访问。对于可读属性,将有一个getter方法来读取属性值。对于可写属性,将有一个setter方法允许更新属性值。
有些框架遵循这些规范,以便通过反射允许注入/检索类字段的值。例如,Spring和JSF。
通过XML配置的Spring示例:
<bean id="fooBean" class="my.package.Foo">
    <property name="stringList">
        <list>
            <value>Hello</value>
            <value>World</value>
        </list>
    </property>
</bean>

以及相关的Java类:

package my.package;

public class Foo {
    private List<String> stringList;
    public String getStringList() {
        return this.stringList;
    }
    //allows Spring to set the value of stringList through reflection
    public void setStringList(List<String> stringList) {
        this.stringList = stringList;
    }
}

使用表达式语言进行字段绑定的JSF示例:
<!-- allows JSF to call getter through reflection -->
<h:dataTable value="#{foo.stringList}" var="value">
    <h:column>
        #{value}
    </h:column>
</h:dataTable>

以及相关的Java类:

package my.package;

@ManagedBean
@ViewScoped
public class Foo {
    private List<String> stringList;
    @PostConstruct
    public void init() {
        stringList = new List<>();
        stringList.add("Hello");
        stringList.add("world");
    }
    public String getStringList() {
        return this.stringList;
    }
    public void setStringList(List<String> stringList) {
        this.stringList = stringList;
    }
}

使用哪个选项:防御性getter/setter还是常规getter/setter?这将取决于你正在做什么。

这个答案非常清晰,代码示例完美地说明和解释了需要做的事情。谢谢。 - Jeremy.S

1

标准做法是使用私有实例变量和公共getter/setter方法(就像你所学的那样)。你总是希望封装或“隐藏”数据,这是面向对象编程的基本概念之一。其中一个主要好处(还有其他)是修改我们实现的代码而不会破坏可能正在使用相同代码的其他开发人员的代码。这种方法还将增加可维护性。


0

我会更进一步:

为什么任何人都需要知道你如何存储数据?信息隐藏是关键词。在你的例子中,有关数据类型的详细信息泄漏到外部。关键字list泄露了实现的细节,这是1)不必要的信息 - 你甚至可以将其命名为treasurechest 2)可能使用你的类的用户对实现做出假设,这是不好的事情。给你的类一个域名,比如goodies,并将方法命名为put/pull。如果你想添加多个元素,我会使用更通用的接口,比如Iterable


0

在一个类中,将全局列表设为私有,并使用getter和setter方法会更好。

使用getter/setter有一些优点:

  • getter和setter可以在其中进行验证,而字段则不能
  • 使用getter,您可以获取所需类的子类。
  • getter和setter是多态的,而字段不是
  • 调试可以更简单,因为断点可以放置在一个方法内,而不是在给定字段的许多引用附近。
  • 它们可以隐藏实现更改

要了解更多详细信息,请查看以下链接

使用set和get方法与公共变量的优势

为什么要使用getter和setter?

:


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