问题

这个问题在这里已有答案:

  • 为什么要使用getter和setter / accessors? [已关闭] 38个答案

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

在快速浏览一下我的代码之后,其中大部分是Getters and Setters(60%),而其余部分则是游戏逻辑真正需要的。

一些谷歌搜索声称Getters和Setter是邪恶的,而其他人声称他们是良好的OO练习和优秀程序所必需的。

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


#1 热门回答(338 赞)

还有一种观点认为,大多数情况下,使用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);

它应该是

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

这可能是一个简单的例子。我想说的是,讨论getter / setter与公共领域的关系经常掩盖了更大的问题,因为对象以一种亲密的方式操纵彼此的内部状态,因此过于紧密耦合。

我们的想法是制定直接做你想做的事情的方法。一个例子是如何设置敌人的"活着"状态。你可能想要使用setAlive(boolean alive)方法。相反,你应该:

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

这样做的原因是,如果你更改实现不再具有"活动"布尔值而非"生命值"值,则可以更改它,而不会破坏你之前编写的两种方法的约定:

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

#2 热门回答(175 赞)

  • 非常邪恶:公共领域。
  • 有点邪恶:吸气剂和制定者不需要他们。
  • 好:只有在真正需要的地方才能获得getter和setter - 使类型暴露出"更大"的行为,恰好使用其状态,而不仅仅是将类型视为要由其他类型操纵的状态存储库。

这实际上取决于情况 - 有时你真的只想要一个愚蠢的数据对象。


#3 热门回答(42 赞)

你已经有了很多很好的答案,所以我只给我两分钱。吸气剂和制定者非常非常邪恶。它们基本上让你假装隐藏你的对象的内部,当你所做的大部分时间被抛在冗余的代码中,没有什么可以隐藏内部状态。对于一个简单的POJO,没有理由不能用obj.name ="Tom"替换getName()和setName()。

如果方法调用只是替换赋值,那么你通过优先选择方法调用获得的只是代码膨胀。不幸的是,该语言已经在JavaBeans规范中规定了getter和setter的使用,因此Java程序员被迫使用它们,即使这样做也毫无意义。

幸运的是,Eclipse(以及可能还有其他IDE)可以让你自动生成它们。对于一个有趣的项目,我曾经在XSLT中为它们构建了一个代码生成器。但是,如果有一件事我会在Java中摆脱它,它过度依赖于getter和setter。


原文链接