我应该使用永远不会改变的字段值的访问器吗?

时间:2012-08-08 00:07:58

标签: java oop encapsulation

我们以这堂课为例:

public class Student{
    private String name;
    private String id;

    public Student(String name, String id){
        this.name = name;
        this.id = id;
    }

    ... getters and setters for both fields

并将其与此进行比较:

public class Student{
    public final String name;
    public final String id;

    public Student(String name, String id){
        this.name = name;
        this.id = id;
    }
 }

我认为不需要访问者 这会被视为糟糕的OO设计吗?

8 个答案:

答案 0 :(得分:7)

这是一个加载的问题。

不幸的是,好(或坏)设计100%取决于它的使用方式。

根据经验,最好将成员变量保持为私有,这样对象模型就可以控制它们的访问权限。这意味着第一种方法更好。

BUT

如果值永远不会改变,重点是什么?如果他们永远不会使用,为什么还要编写setter?

那么哪一个更好?正如我上面提到的,这取决于你为此做了什么。如果它是为了课程的作业,我会选择第一个。你的老师会更喜欢这样,因为它更像是“教科书”。

所以,如果这是一个个人项目,或者你可以利用未来版本的工作,我会在两者之间进行交叉:

public class Student{
    private final String name;
    private final String id;

    public Student(String name, String id){
        this.name = name;
        this.id = id;
    }

  ... getters ONLY for both fields

这种方法是安全的,因为成员字段是私有的,并且没有未使用方法的“代码味道”。这也是相当可扩展的,因为如果您的需求发生变化并且您需要修改字段,则可以非常轻松地添加setter。

答案 1 :(得分:6)

你应该始终致力于将可变性和范围限制在最低限度。在你的情况下:将字段设为私有,最终,使用getter,不使用setter。

奖励:您的班级将变为immutable并且线程安全。

另见this post

答案 2 :(得分:2)

Getter和Setter使API更稳定。例如,考虑一个由其他类访问的类中的字段public。现在稍后,您希望在获取和设置变量时添加任何额外的逻辑。这将影响使用API​​的现有客户端。因此,对此公共字段的任何更改都需要更改引用它的每个类。相反,使用访问器方法,可以轻松添加一些逻辑,如缓存一些数据,稍后懒洋洋地初始化它。此外,如果新值与先前值不同,则可以触发属性更改事件。所有这些都将与使用访问器方法获得价值的类无缝连接。

ThePragmaticProgrammer建议也总是使用getter和setter,因为它是更通用的接口。查看这篇文章http://c2.com/cgi/wiki?AccessorsAreEvil它非常好,并深入理解我们应该使用它们的原因。

答案 3 :(得分:0)

当然,如果你知道它们永远不会改变,那么你就不需要访问器了。

但如果你告诉我你确定他们永远不会改变,我就不相信你。

答案 4 :(得分:0)

如果字段为final,那么您实际上不需要使用getter / setter。因为它们永远不会改变,所以setter也会毫无意义。

答案 5 :(得分:0)

一致性规则。如果你有一些类/属性可以公开访问变量而其他人有“getters”,那么它就不是一个好地方。

假设您接受Student课程并添加java.util.Date字段。

public final Date dateOfBirth;

唉,现在你Student以不受控制的方式变异了。我们需要。

private final Date dateOfBirth;
...
public Date dateOfBirth() {
     return new Date(dateOfBirth.getTime()); // Awful API.
}

通常,只需将每个(实例)字段设为私有(数据传输对象的例外)。如果你有setter,那么你可能已经放弃了封装的所有希望。 Getters适用于不可变值对象。 (“get”前缀是Java的约定(主要是),但它主要是噪声,特别是在有利于不可变值对象和tell-not-ask接口的代码中。如果删除“get”,则客户端代码只有额外的“()”作为直接现场访问的详细程度。)

答案 6 :(得分:0)

那里有一些很好的答案,我同意将字段设为私有,并添加适当的构造函数/ getter / setter来限制需要的可变性。

我将指出使用基于字段的分配的另一个缺点。任何基于代理的AOP都会在向字段分配添加切入点时遇到问题,因此很难通过基于代理的AOP构造进行日志记录(以及其他操作),因为它们仅限于方法拦截。你最有可能真正进行编织,这变得更加复杂。从Spring自己的文档:

  

Spring AOP目前仅支持方法执行连接点   (建议在Spring bean上执行方法)。领域   拦截没有实施,虽然支持现场   可以在不破坏核心Spring AOP API的情况下添加拦截。   如果您需要建议现场访问和更新连接点,请考虑a   像AspectJ这样的语言。

答案 7 :(得分:-1)

我认为这不是一个坏主意。

如果它们不会更改,请确保使用相应的关键字标记字段,例如Final

使非变化值以不同方式显示也是一个好主意。例如,Java中的常量通常以全部大写形式完成。