我们以这堂课为例:
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设计吗?
答案 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中的常量通常以全部大写形式完成。