使用getter和setter(只获取和设置)而不是简单地为这些变量使用公共字段有什么好处?

如果getter和setter所做的不仅仅是简单的get/set,我可以很快地解决这个问题,但我不是100%清楚如何做到:

public String foo;

比:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

而前者需要的样板代码要少得多。


当前回答

谢谢,这真的澄清了我的想法。现在有10个(几乎)不使用getter和setter的好理由:

当您意识到您需要做的不仅仅是设置和获取值时,您可以将字段设为私有,这会立即告诉您直接访问它的位置。在那里执行的任何验证都只能是上下文无关的,而实际上很少进行这种验证。您可以更改设置的值-当调用者传递给您一个他们(震惊恐惧)希望您按原样存储的值时,这绝对是一场噩梦。你可以隐藏内部表示-太棒了,所以你要确保所有这些操作都是对称的,对吗?你已经将你的公共界面与表单下的更改隔离开来——如果你在设计一个界面,但不确定直接访问某个东西是否可行,那么你应该继续设计。一些库期望这样做,但并不多——反射、序列化、模拟对象都能很好地处理公共字段。通过继承这个类,您可以覆盖默认功能——换句话说,您不仅可以隐藏实现,而且可以使其不一致,从而真正混淆调用者。

最后三个我要离开(N/A或D/C)。。。

其他回答

另一个用途(在支持财产的语言中)是setter和getter可以暗示操作是非平凡的。通常,您希望避免在属性中执行任何计算成本高昂的操作。

取决于你的语言。您已经将其标记为“面向对象”而不是“Java”,因此我想指出ChssPly76的答案依赖于语言。例如,在Python中,没有理由使用getter和setter。如果需要更改行为,可以使用一个属性,该属性将getter和setter包装在基本属性访问周围。类似于:

 class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)

Getter和setter用于实现面向对象编程的两个基本方面,即:

抽象封装

假设我们有一个Employee类:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

与公共属性不同,全名的实现细节对用户隐藏,用户无法直接访问。

我想发布一个我刚刚完成的真实世界示例:

背景-我使用休眠工具为我的数据库生成映射,这是一个我在开发时正在更改的数据库。我更改数据库模式,推送更改,然后运行hibernate工具来生成java代码。在我想向这些映射实体添加方法之前,一切都很好。如果我修改了生成的文件,则每次对数据库进行更改时都会覆盖这些文件。所以我这样扩展生成的类:

package com.foo.entities.custom
class User extends com.foo.entities.User{
     public Integer getSomething(){
         return super.getSomething();             
     }
     public void setSomething(Integer something){
         something+=1;
         super.setSomething(something); 
     }
}

我上面所做的是用我的新功能(something+1)覆盖超类上的现有方法,而不需要接触基类。如果你在一年前写了一个类,并且想在不改变基类的情况下升级到第2版(测试噩梦),也是同样的情况。希望这会有所帮助。

根据我的经验,最好将变量设置为私有,并为每个变量提供访问器和修饰符。

通过这种方式,您可以根据需要创建只读变量,也可以只写变量。

下面的实现显示了一个只写变量。

private String foo;
public void setFoo(String foo) { this.foo = foo; }
private String getFoo() { return foo; }

下面显示了一个只读变量。

private String foo;
private void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }