【问题标题】:Private List with Getter/Setter vs Public List带有 Getter/Setter 的私有列表与公共列表
【发布时间】:2014-07-21 21:57:04
【问题描述】:

在一个类中创建一个全局 List 并具有 getter 和 setter 方法会更好,还是将其公开会更好? Java的标准是什么?

我被教导将变量设为私有,并且只有 getter 和 setter 方法,但访问公共列表肯定比访问私有列表更好。

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

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

这是我的意见,但我当然更愿意按照标准而不是看起来不错。

【问题讨论】:

  • 将私有实例成员与公共 getter/setter 一起使用是避免对变量状态进行不必要修改的好方法。这里的 setter 方法作为安全卫士。它提供单点联系。阅读更多关于Encapsulation
  • 为什么没有一个方法add() 接受对象"Candy" 并将其添加到列表中? classThatContainsTheList.add("Candy"); ?
  • 虽然不是一成不变的,Law of Demeter 在这些情况下提供了一些很好的建议。
  • @AntonH 如果我这样做了,我不需要添加与集合相关的所有其他方法吗?不是必需的,但如果我要使用它们,我也可以。
  • @dalawh 您添加了提供所需功能的方法。如果您只需要添加和删除,只需使用执行这些操作的方法即可。这些方法将以经典方式作用于列表。我并不是说这是最好的方法,但可以考虑。

标签: java list getter access-modifiers


【解决方案1】:

标准是拥有私有实例变量和公共 getter/setter 方法(就像你被教导的那样)。您总是希望封装或“隐藏”数据,这是 OOP 的基本概念之一。这样做的主要好处之一(除其他外)是在不破坏可能使用相同代码的其他开发人员的代码的情况下修改我们实现的代码。这种方法还将增加可维护性。

【讨论】:

    【解决方案2】:

    我会更进一步:

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

    【讨论】:

      【解决方案3】:

      最好在类中创建一个全局 List 并具有 getter 和 setter 方法

      使用 getter/setter 有一些优点

      • getter 和 setter 可以在其中进行验证,字段不能
      • 使用 getter 可以获得想要的类的子类。
      • getter 和 setter 是多态的,字段不是
      • 调试可以简单很多,因为可以下断点 在一个方法中,该给定字段的引用并不多。
      • 他们可以隐藏实现更改

      要了解更多详细信息,请访问以下链接

      Advantage of set and get methods vs public variable

      Why use getters and setters?

      【讨论】:

        【解决方案4】:

        首先,您不应该直接使用public 字段,除非它们是常量 (static final) 字段并且确保它们的状态不会改变。应该使用Encapsulation 公开它们,以避免您的班级的客户修改状态。这是一个通过以防御方式实现 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 specification 声明 Java 类中的字段不应为 public,并且应通过 getter 和 setter 方法访问它们。

        7 属性

        属性是 Java Bean 的离散的、命名的属性,可以影响其外观或行为。例如,一个 GUI 按钮可能有一个名为“Label”的属性,它表示按钮中显示的文本。

        属性以多种方式显示:

        1. 属性可能会在脚本环境中公开,就好像它们是 对象。因此,在 Javascript 环境中,我可能会执行“b.Label = foo”来设置 a 的值 财产。
        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;
            }
        }
        

        使用Expression Language进行字段绑定的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?这取决于你在做什么。

        【讨论】:

        • 这个答案非常清楚,代码示例说明并解释了需要完美完成的工作。谢谢。
        猜你喜欢
        • 2017-06-27
        • 2017-01-17
        • 1970-01-01
        • 1970-01-01
        • 2018-08-06
        • 2014-06-18
        • 2018-07-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多