使用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; }

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


当前回答

取决于你的语言。您已经将其标记为“面向对象”而不是“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)

其他回答

很多人都在谈论二传手和二传手的优点,但我想扮演魔鬼代言人的角色。现在我正在调试一个非常大的程序,程序员们决定让所有的东西都变得更好和更好。这看起来不错,但这是一场逆向工程噩梦。

假设你正在查看数百行代码,你会发现:

person.name = "Joe";

这是一段非常简单的代码,直到你意识到它是一个setter。现在,您遵循该setter,发现它还设置了person.firstName、person.lastName、person.isHuman、person.hasReallyCommonFirstName,并调用person.update(),后者将查询发送到数据库等。哦,这就是发生内存泄漏的地方。

乍一看就理解一段本地代码是具有良好可读性的一个重要特性,getter和setter往往会打破这一特性。这就是为什么我尽量避免使用它们,并在使用它们时尽量减少它们所做的事情。

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

背景-我使用休眠工具为我的数据库生成映射,这是一个我在开发时正在更改的数据库。我更改数据库模式,推送更改,然后运行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版(测试噩梦),也是同样的情况。希望这会有所帮助。

我能想到一个原因,为什么你不希望一切都公开。

例如,您从未打算在类外部使用的变量可以被访问,甚至可以通过链变量访问(即object.item.origin.x)直接访问。

通过将所有内容都设为私有,并且仅将您想要扩展的内容以及可能在子类中引用的内容设为受保护的,并且通常只将静态最终对象设为公共,那么您就可以通过使用setter和getter访问您想要的程序内容来控制其他程序员和程序可以在API中使用什么,以及它可以访问什么,以及不能访问什么,或者可能是其他恰好使用您的代码的程序员,可以在您的程序中进行修改。

考虑使用访问器是有充分理由的,因为没有属性继承。请参见下一个示例:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

输出:

0
0
4

在面向对象的语言中,方法及其访问修饰符声明该对象的接口。在构造函数、访问器和赋值器方法之间,开发人员可以控制对对象内部状态的访问。如果变量被简单地声明为公共的,那么就没有办法规范这种访问。当我们使用setter时,我们可以限制用户所需的输入。这意味着这个变量的输入将通过一个适当的通道,通道是我们预先定义的。所以使用setter更安全。