使用 getter 还是直接访问私有成员更好?
Is it better to use getters or to access private members directly?
下面哪个比较好?它甚至是基于意见还是有任何相关差异?在某些情况下可以偏爱其中之一吗?
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);
}
编辑:
此 post 在链接问题中没有答案(请参阅对初始 post 的评论)
在我的软件工程课程中,我被告知要实现 "principle of secret"。因此,您应该始终使用 getter- 和 setter- 例程。这样可以确保没有人意外访问成员变量。
奇怪的函数或对象可能永远不会看到甚至更改成员变量,除非您通过 setter 和 getters 明确告诉它们这样做。
我建议使用 getter,因为在某些情况下,它可以有一些额外的逻辑(如格式化、检查空值等)。因此,您在使用字段本身时可能会失去一些逻辑。
由于您的属性是私有的,您只能在其他 class 中使用 getter 或 setter 方法安全地访问它。所以我想说最好的实现是遵循封装原则的,即使用getter而不是直接访问的那种。
这也将防止数据泄漏。
Which of the following is better? Is it even opinion-based or are
there any relevant differences? Can one or the other be favored in
some scenarios?
我认为这是良好实践的问题。区别在于代码的可读性。
一般来说,如果不需要,您应该避免间接访问。
MyClass
的当前实例具有这些字段之一中的信息以实现该操作。它不需要向自己隐藏其内部状态。
所以在内部,MyClass
没有有价值的理由支持使用 getMyField()
而不是直接使用 myField
字段。
getMyField()
访问器更适合 class.
的客户端使用
所以我认为在您的示例代码中无论如何都更好:
public boolean isAllowed() {
MyEnum.ALLOWED.getInt().equals(myField);
}
编辑 :
除了可读性之外,这是一个示例,为什么您没有兴趣将内部状态耦合到 public getter.
假设在开发阶段您从 class 中删除了 public getMyField()
方法,因为 class 的客户不再需要或不再需要,如果 isAllowed()
依赖于 getMyField()
在它的实现中,它会被破坏,你应该用 myField
.
替换它
为了保持良好的封装,您首先需要考虑的是您要在 class 之外公开哪些方法,如果在这里,例如您将只使用 is allowed 方法,我只会 public 那个方法,并在构造函数中定义字段,如果该字段适合更改那么你将需要 getter/setters 但总是取决于你想从你的 class。并尽可能多地封装。
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);
}
}
我的回答不会是最有用的,但是它将来自处理这种模式的直接经验。在设计对象时,通常很想直接访问成员字段而不是依赖访问器。这种愿望源于想要简化对象并避免从简单 return 值的方法中添加混乱。将您的示例进一步添加上下文和含义:
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;
}
}
这里的年龄是一个简单的数字,似乎没有必要在它周围添加 getters/setters。如果我们添加以下方法,您可能会想直接访问该字段,因为行为没有变化:
public Integer calculateScore() {
if(age > 21) return 100 - getNumberOfIncorrectAnswers();
//Add 10% before for younger students
else return (100 - getNumberOfIncorrectAnswers()) + 10;
}
然后,您的对象可能会使用依赖于您继续直接使用它的年龄字段的方法来增加新功能。稍后,您可能会改变年龄的产生方式并从网络中提取价值。您可能不想在构造函数中合并网络逻辑,因为它是一项昂贵的操作,应该只在需要时触发。 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,从一开始就练习封装仍然是有利的。
下面哪个比较好?它甚至是基于意见还是有任何相关差异?在某些情况下可以偏爱其中之一吗?
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);
}
编辑: 此 post 在链接问题中没有答案(请参阅对初始 post 的评论)
在我的软件工程课程中,我被告知要实现 "principle of secret"。因此,您应该始终使用 getter- 和 setter- 例程。这样可以确保没有人意外访问成员变量。
奇怪的函数或对象可能永远不会看到甚至更改成员变量,除非您通过 setter 和 getters 明确告诉它们这样做。
我建议使用 getter,因为在某些情况下,它可以有一些额外的逻辑(如格式化、检查空值等)。因此,您在使用字段本身时可能会失去一些逻辑。
由于您的属性是私有的,您只能在其他 class 中使用 getter 或 setter 方法安全地访问它。所以我想说最好的实现是遵循封装原则的,即使用getter而不是直接访问的那种。 这也将防止数据泄漏。
Which of the following is better? Is it even opinion-based or are there any relevant differences? Can one or the other be favored in some scenarios?
我认为这是良好实践的问题。区别在于代码的可读性。
一般来说,如果不需要,您应该避免间接访问。
MyClass
的当前实例具有这些字段之一中的信息以实现该操作。它不需要向自己隐藏其内部状态。
所以在内部,MyClass
没有有价值的理由支持使用 getMyField()
而不是直接使用 myField
字段。
getMyField()
访问器更适合 class.
的客户端使用
所以我认为在您的示例代码中无论如何都更好:
public boolean isAllowed() {
MyEnum.ALLOWED.getInt().equals(myField);
}
编辑 :
除了可读性之外,这是一个示例,为什么您没有兴趣将内部状态耦合到 public getter.
假设在开发阶段您从 class 中删除了 public getMyField()
方法,因为 class 的客户不再需要或不再需要,如果 isAllowed()
依赖于 getMyField()
在它的实现中,它会被破坏,你应该用 myField
.
为了保持良好的封装,您首先需要考虑的是您要在 class 之外公开哪些方法,如果在这里,例如您将只使用 is allowed 方法,我只会 public 那个方法,并在构造函数中定义字段,如果该字段适合更改那么你将需要 getter/setters 但总是取决于你想从你的 class。并尽可能多地封装。
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);
}
}
我的回答不会是最有用的,但是它将来自处理这种模式的直接经验。在设计对象时,通常很想直接访问成员字段而不是依赖访问器。这种愿望源于想要简化对象并避免从简单 return 值的方法中添加混乱。将您的示例进一步添加上下文和含义:
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;
}
}
这里的年龄是一个简单的数字,似乎没有必要在它周围添加 getters/setters。如果我们添加以下方法,您可能会想直接访问该字段,因为行为没有变化:
public Integer calculateScore() {
if(age > 21) return 100 - getNumberOfIncorrectAnswers();
//Add 10% before for younger students
else return (100 - getNumberOfIncorrectAnswers()) + 10;
}
然后,您的对象可能会使用依赖于您继续直接使用它的年龄字段的方法来增加新功能。稍后,您可能会改变年龄的产生方式并从网络中提取价值。您可能不想在构造函数中合并网络逻辑,因为它是一项昂贵的操作,应该只在需要时触发。 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,从一开始就练习封装仍然是有利的。