Java getter 和 setter 是糟糕的设计吗?看到了矛盾的建议

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/565095/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 16:17:33  来源:igfitidea点击:

Are getters and setters poor design? Contradictory advice seen

javaoopsettergetteraccessor

提问by Mike B

I'm currently working on a simple game in Java with several different modes. I've extended a main Game class to put the main logic within the other classes. Despite this, the main game class is still pretty hefty.

我目前正在用几种不同的模式用 Java 开发一个简单的游戏。我扩展了一个主要的 Game 类,将主要逻辑放在其他类中。尽管如此,主要的游戏类仍然相当庞大。

After taking a quick look at my code the majority of it was Getters and Setters (60%) compared to the rest that is truly needed for the logic of the game.

快速浏览我的代码后,与游戏逻辑真正需要的其余部分相比,其中大部分是 Getters 和 Setters (60%)。

A couple of Google searches have claimed that Getters and Setters are evil, whilst others have claimed that they are necessary for good OO practice and great programs.

一些谷歌搜索声称 Getter 和 Setter 是邪恶的,而其他人则声称它们对于良好的 OO 实践和伟大的程序是必要的。

So what should I do? Which should it be? Should I be changing my Getters and Setters for my private variables, or should I stick with them?

所以我该怎么做?应该是哪个?我应该为我的私有变量更改我的 Getter 和 Setter,还是应该坚持使用它们?

采纳答案by Zarkonnen

There is also the point of view that most of the time, using setters still breaks encapsulation by allowing you to set values that are meaningless. As a very obvious example, if you have a score counter on the game that only ever goes up, instead of

还有一种观点认为,在大多数情况下,使用 setter 仍然会通过允许您设置无意义的值来破坏封装。举一个非常明显的例子,如果你在游戏中有一个只会上升的分数计数器,而不是

// Game
private int score;
public void setScore(int score) { this.score = score; }
public int getScore() { return score; }
// Usage
game.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);

it should be

它应该是

// Game
private int score;
public int getScore() { return score; }
public void addScore(int delta) { score += delta; }
// Usage
game.addScore(ENEMY_DESTROYED_SCORE);

This is perhaps a bit of a facile example. What I'm trying to say is that discussing getter/setters vs public fields often obscures bigger problems with objects manipulating each others' internal state in an intimate manner and hence being too closely coupled.

这也许是一个简单的例子。我想说的是,讨论 getter/setter 与 public 字段通常会掩盖更大的问题,即对象以亲密的方式操纵彼此的内部状态,因此耦合过于紧密。

The idea is to make methods that directly do things you want to do. An example would be how to set enemies' "alive" status. You might be tempted to have a setAlive(boolean alive) method. Instead you should have:

这个想法是制作直接做你想做的事情的方法。一个例子是如何设置敌人的“活着”状态。您可能想拥有一个 setAlive(boolean alive) 方法。相反,你应该有:

private boolean alive = true;
public boolean isAlive() { return alive; }
public void kill() { alive = false; }

The reason for this is that if you change the implementation that things no longer have an "alive" boolean but rather a "hit points" value, you can change that around without breaking the contract of the two methods you wrote earlier:

这样做的原因是,如果您更改实现,即事物不再具有“活动”布尔值而是“命中点”值,则可以在不破坏之前编写的两种方法的约定的情况下进行更改:

private int hp; // Set in constructor.
public boolean isAlive() { return hp > 0; } // Same method signature.
public void kill() { hp = 0; } // Same method signature.
public void damage(int damage) { hp -= damage; }

回答by Jon Skeet

  • Very evil: public fields.
  • Somewhat evil: Getters and setters where they're not required.
  • Good: Getters and setters only where they're really required - make the type expose "larger" behaviour which happens to useits state, rather than just treating the type as a repository of state to be manipulated by other types.
  • 非常邪恶:公共领域。
  • 有点邪恶:不需要的吸气剂和二传手。
  • 好:Getter 和 setter 只在真正需要的地方 - 使类型暴露“更大”的行为,它碰巧使用其状态,而不是仅仅将类型视为由其他类型操作的状态存储库。

It really depends on the situation though - sometimes you really dojust want a dumb data object.

这真的取决于虽然形势-有时候你真的只是想要一个愚蠢的数据对象。

回答by Joonas Pulakka

My opinion is that getters and setters are a requirement for good programs. Stick with them, but don't write unnecessary getters/setters - it's not always necessary to directly deal with all variables.

我的观点是 getter 和 setter 是好程序的必要条件。坚持使用它们,但不要编写不必要的 getter/setter - 并不总是需要直接处理所有变量。

回答by David Segonds

You may want to replace some of your classes by value classes. This will allow you to remove the getter and avoid problems when the content is changed from under you.

您可能希望用值类替换某些类。这将允许您删除 getter 并避免在您更改内容时出现问题。

回答by Jeroen van Bergen

As always the only answer is: it depends. If you are the only peron touching the code, you can do anything you're comfortable with, including taking shortcuts.

与往常一样,唯一的答案是:视情况而定。如果你是唯一接触代码的人,你可以做任何你觉得舒服的事情,包括走捷径。

One of the benefits of using setters is that checks need to be performed at only one location in your code.

使用 setter 的好处之一是只需在代码中的一个位置执行检查。

You might want to pay some closer attention to what is actually being get and set by these methods. If you're using them to provide access to constant values you are probably better off by using constants.

您可能需要更密切地关注这些方法实际获取和设置的内容。如果您使用它们来提供对常量值的访问,那么使用常量可能会更好。

回答by philsquared

If you need external access to individual values of fields, use getters and/ or setters. If not, don't. Never use public fields. It's as simple as that! (Ok, it's never thatsimple, but it's a good rule of thumb).

如果您需要对字段的各个值进行外部访问,请使用 getter 和/或 setter。如果没有,不要。永远不要使用公共字段。就这么简单!(好吧,这从来都不是那么简单,但这是一个很好的经验法则)。

In general you should also find that you need to supply a setter much less often than a getter - especially if you are trying to make your objects immutable - which is a Good Thing (but not always the best choice) - but even if not.

一般来说,您还应该发现与 getter 相比,您需要提供 setter 的频率要低得多——特别是如果您试图使对象不可变——这是一件好事(但并不总是最好的选择)——但即使不是。

回答by Michael Borgwardt

Your Game class is probably following the god objectantipattern if it exposes that many variables. There's nothing wrong with getters and setters (though their verbosity in Java can be a bit annoying); in a well-designed app where each class has a clearly separated functionality, you will not need dozens of them in a single class.

如果你的 Game 类暴露了那么多变量,它可能会遵循God 对象反模式。getter 和 setter 没有任何问题(尽管它们在 Java 中的冗长可能有点烦人);在一个设计良好的应用程序中,每个类都有明确分开的功能,你不需要在一个类中包含几十个。

Edit:If the main point for the getters and setters is to "configure" the game classe (I understand your comment that way), then your probably don't need the getters (it's perfectly fine for a class to access its own private variables without using get methods), and you can probably collapse many of the setters into "group setters" that set several variables which belong together conceptually.

编辑:如果 getter 和 setter 的主要目的是“配置”游戏类(我理解你的评论),那么你可能不需要 getter(类访问它自己的私有变量完全没问题)不使用 get 方法),并且您可能可以将许多设置器折叠为“组设置器”,这些设置器设置几个概念上属于一起的变量。

回答by Michael Borgwardt

This depends on the programming language in question. Your question is framed in the context of Java, where it seems that getters and setters are generally thought of as a good thing.

这取决于所讨论的编程语言。您的问题是在 Java 上下文中提出的,在 Java 中,getter 和 setter 似乎通常被认为是一件好事。

In contrast, in the Python world, they are generally considered as bad style: they add lines to the code without actually adding functionality. When Python programmers need to, they can use metaprogramming to catch getting and/or setting of object attributes.

相比之下,在 Python 世界中,它们通常被认为是糟糕的风格:它们在代码中添加了行,而没有实际添加功能。当 Python 程序员需要时,他们可以使用元编程来捕获对象属性的获取和/或设置。

In Java (at least the version of Java I learned slightly a decade ago), that was not possible. Thus, in Java it is usually best to use getters and setters religiously, so that if you need to, you can override access to the variables.

在 Java(至少是我十年前稍微学到的 Java 版本)中,这是不可能的。因此,在 Java 中,通常最好虔诚地使用 getter 和 setter,以便在需要时可以覆盖对变量的访问。

(This doesn't make Python necessarily better than Java, just different.)

(这并不意味着 Python 一定比 Java 好,只是不同而已。)

回答by Tom Hawtin - tackline

The presence of getter and setters tends to indicate (a "smell" if you are into that sort of primary school language) that there is a design problem. Trivial getters and setters are barely distinguishable from public fields. Typically the code operating on the data will be in a different class - poor encapsulation, and what you would expect from programmers not at ease with OO.

getter 和 setter 的存在往往表明(如果你是那种小学语言的“气味”)存在设计问题。普通的 getter 和 setter 与公共字段几乎没有区别。通常,对数据进行操作的代码将位于不同的类中 - 封装不佳,并且您期望程序员对 OO 不放心。

In some cases getters and setters are fine. But as a rule a type with both getters and setters indicates design problems. Getters work for immutability; setters work for "tell don't ask". Both immutability and "tell don't ask" are good design choices, so long as they are not applied in an overlapping style.

在某些情况下,getter 和 setter 很好。但作为规则,同时具有 getter 和 setter 的类型表示设计问题。Getter 为不变性而工作;二传手为“告诉不要问”而工作。不变性和“告诉不要问”都是不错的设计选择,只要它们不以重叠的方式应用即可。

回答by gustafc

Just FYI: In addition to all the excellent answers in this thread, remember that of all reasons you can come up with for or against getters/setters, performance isn't one (as some might believe). The JVM is smart enough to inline trivial getters/setters (even non-finalones, as long as they aren't actually overridden).

仅供参考:除了本主题中所有出色的答案之外,请记住,在您可以提出支持或反对 getter/setter 的所有原因中,性能不是一个(正如某些人可能认为的那样)。JVM 足够聪明,可以内联简单的 getter/setter(即使是非 getter/setter final,只要它们实际上没有被覆盖)。

回答by joel.neely

It's a slippery slope.

这是一个滑坡。

A simple Transfer object (or Parameter object) may have the sole purpose of holding some fields and providing their values on demand. However, even in that degenerate case one could argue that the object should be immutable -- configured in the constructor and exposing only get... methods.

一个简单的 Transfer 对象(或 Parameter 对象)的唯一目的可能是保存一些字段并根据需要提供它们的值。然而,即使在这种退化的情况下,人们也可能会争辩说对象应该是不可变的——在构造函数中配置并只公开get... 方法。

There's also the case of a class that exposes some "control knobs"; your car radio's UI probably can be understood as exposing something like getVolume, setVolume, getChannel, and setChannel, but its real functionality is receiving signals and emitting sound. But those knobs don't expose much implementation detail; you don't know from those interface features whether the radio is transistors, mostly-software, or vacuum tubes.

还有一个类暴露了一些“控制旋钮”的情况;你的汽车收音机的用户界面大概可以理解为暴露类似getVolumesetVolumegetChannel,和setChannel,但其真正的功能是接收信号并发出声音。但是这些旋钮并没有暴露太多的实现细节;你无法从这些界面功能中知道收音机是晶体管,主要是软件还是真空管。

The more you begin to think of an object as an active participant in a problem-domain task, the more you'll think in terms of asking it to do somethinginstead of asking it to tell you about its internal state, or asking it for its data so other codecan do something with those values.

您越开始将对象视为问题域任务的积极参与者,您就越会考虑要求它做某事,而不是要求它告诉您其内部状态,或要求它提供它的数据,以便其他代码可以对这些值执行某些操作。

So... "evil"? Not really. But every time you're inclined to put in a value and expose both get... and set... methods on that value, ask yourself why, and what that object's reponsibility really is. If the only answer you can give yourself is, "To hold this value for me", then maybesomething besides OO is going on here.

所以……“邪恶”?并不真地。但是每次您倾向于放入一个值并在该值上公开get... 和set... 方法时,问问自己为什么,以及该对象的真正职责是什么。如果您能给自己的唯一答案是“为我保留这个价值”,那么这里可能发生了 OO 之外的其他事情。