使用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案例,我相信真正的原因是:

接口的代码,而不是实现接口只指定方法,不指定字段

换句话说,在接口中指定字段的唯一方法是提供一个用于写入新值的方法和一个用于读取当前值的方法。

这些方法是臭名昭著的getter和setter。。。。

其他回答

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

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

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

我知道现在有点晚了,但我想有些人对表演感兴趣。

我做了一个性能测试。我写了一个类“NumberHolder”,它包含一个整数。您可以使用getter方法读取该IntegeranInstance.getNumber()或通过使用anInstance.number直接访问数字。我的程序通过两种方式读取数字1000000000次。该过程重复五次,并打印时间。我得到了以下结果:

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(时间1是直接方式,时间2是吸气方式)

你看,吸气器(几乎)总是快一点。然后我尝试了不同次数的循环。我用了1000万和10万,而不是100万。结果:

1000万次循环:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

1000万次循环,时间几乎相同。以下是10万(10万)个循环:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

同样,对于不同数量的循环,getter比常规方法快一点。我希望这对你有所帮助。

原因有很多。我最喜欢的是当你需要改变行为或调整你可以设置的变量时。例如,假设您有一个setSpeed(intspeed)方法。但你希望你只能将最大速度设置为100。您可以执行以下操作:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

现在,如果代码中的每个地方都使用公共字段,然后意识到需要上述要求,该怎么办?寻找公共领域的每一种用法,而不仅仅是修改你的setter。

我的2美分:)

我们使用getter和setter:

可重用性在编程的后期执行验证

Getter和setter方法是访问私有类成员的公共接口。


封装咒语

封装的口头禅是将字段私有化,将方法公开化。

Getter方法:我们可以访问私有变量。Setter方法:我们可以修改私有字段。

尽管getter和setter方法没有添加新的功能,但我们可以稍后再改变主意,制作该方法

较好的更安全的;和更快。


只要可以使用值,就可以添加返回该值的方法。而不是:

int x = 1000 - 500

use

int x = 1000 - class_name.getValue();

用外行的话来说

假设我们需要存储此人的详细信息。此人具有姓名、年龄和性别字段。要做到这一点,需要创建姓名、年龄和性别的方法。现在,如果我们需要创建另一个人,就需要重新创建姓名、年龄和性别的方法。

我们可以使用getter和setter方法创建一个bean类(Person),而不是这样做。因此,明天我们只要在需要添加新人员时创建这个Bean类(Person类)的对象即可(见图)。因此,我们重用bean类的字段和方法,这要好得多。

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叔叔)的“清洁代码”