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

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


当前回答

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

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更安全。

因为从现在起2周(月、年),当您意识到setter需要做的不仅仅是设置值时,您还将意识到该属性已直接用于238个其他类:-)

访问器和赋值器的一个优点是可以执行验证。

例如,如果foo是公共的,我可以很容易地将其设置为null,然后其他人可以尝试调用对象上的方法。但它已经不在了!使用setFoo方法,我可以确保foo从未设置为null。

访问器和赋值器也允许封装-如果你不应该在值设置后看到它(也许它在构造函数中设置,然后被方法使用,但不应该被更改),那么任何人都不会看到它。但如果您允许其他类查看或更改它,则可以提供适当的访问器和/或赋值器。

DataStructure和Object之间存在差异。

数据结构应该暴露其内部而不是行为。

一个物体不应该暴露其内部,但它应该暴露其行为,这也被称为德米特定律

大多数DTO被认为是一种数据结构,而不是对象。他们应该只公开自己的数据,而不是行为。在数据结构中设置Setter/Getter将暴露行为,而不是其中的数据。这进一步增加了违反德梅特定律的可能性。

鲍勃叔叔在他的《干净的代码》一书中解释了得墨忒耳定律。

有一种著名的启发式方法叫做得墨忒耳定律,它说:模块不应该知道它的对象的内部结构操纵。正如我们在上一节中看到的,对象隐藏其数据并暴露操作。这意味着对象不应公开其通过访问器的内部结构,因为这样做是为了暴露,而不是隐藏其内部结构。更准确地说,德米特定律说C类的方法f应仅调用以下方法:Cf创建的对象作为参数传递给f的对象保存在C的实例变量中的对象该方法不应在任何允许的函数返回的对象上调用方法。换句话说,与朋友交谈,而不是与陌生人交谈。

因此,根据这一点,LoD违规的例子是:

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

在这里,函数应该调用它的直接朋友的方法,这里是ctxt,它不应该调用它直接朋友的朋友的方法。但该规则不适用于数据结构。所以在这里,如果ctxt、option、scratchDir是数据结构,那么为什么要用一些行为包装它们的内部数据,并违反LoD。

相反,我们可以这样做。

final String outputDir = ctxt.options.scratchDir.absolutePath;

这满足了我们的需求,甚至没有违反LoD。

灵感来源于Robert C.Martin(Bob叔叔)的“清洁代码”

从面向对象设计的角度来看,这两种选择都会削弱类的封装,从而对代码的维护造成损害。对于讨论,您可以查看这篇优秀的文章:http://typicalprogrammer.com/?p=23