getter和setter是不好的devise? 矛盾的build议看到

我目前正在用几种不同的模式在Java中进行一个简单的游戏。 我已经扩展了一个主要的Game类,把主要的逻辑放在其他类中。 尽pipe如此,主要的游戏类仍然非常沉重。

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

一些谷歌search声称吸气剂和定型剂是邪恶的,而其他人声称,他们是良好的面向对象实践和伟大的计划所必需的。

所以我该怎么做? 应该是哪一个? 我应该改变我的Getters和Setter为我的私有variables,还是应该坚持他们?

还有一种观点认为,大多数时候,使用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 / setters与public fields往往会掩盖更大的问题,因为对象互相操纵彼此的内部状态,因此过于紧密地耦合在一起。

这个想法是让方法直接做你想做的事情。 一个例子就是如何设置敌人的“活着”状态。 你可能会想要一个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; } 
  • 非常邪恶:公共领域。
  • 有些邪恶:吸气剂和安装者不需要的地方。
  • 好:Getters和Setter只在真正需要的地方 – 使types暴露出使用其状态的“更大”的行为,而不仅仅是将types视为由其他types操纵的状态的存储库。

这真的取决于情况 – 有时你真的只是想要一个愚蠢的数据对象。

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

如果方法调用只是取代赋值,那么通过方法调用获得的所有内容都是代码膨胀。 不幸的是,这个语言已经在JavaBeans规范中使用了getter和setter,所以Java程序员被迫使用它们,即使这样做也没有任何意义。

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

Getters和Setter在面向对象的编程中实现了封装的概念。

通过使对象的状态隐藏于外部世界,对象确实负责自身,不能以非意图的方式改变。 对象可以被操纵的唯一方法是通过暴露的公共方法,比如getter和setter。

有getter和setter有几个好处:

1.允许将来修改而不修改使用修改后的类的代码。

使用getter和setter的一个最大的好处是,一旦定义了公共方法,并且需要改变底层实现(例如find一个需要修复的bug,使用不同的algorithm来提高性能等等),通过使得getter和setter成为操作对象的唯一方式,它将允许现有的代码不会中断,并且即使在更改后也能按预期工作。

例如,假设有一个setValue方法在对象中设置value私有variables:

 public void setValue(int value) { this.value = value; } 

但是,接下来需要跟踪value变化的次数。 随着二传手的到位,改变是相当微不足道的:

 public void setValue(int value) { this.value = value; count++; } 

如果value是公开的,那么稍后再回来就没有简单的方法,并添加一个跟踪值更改次数的计数器。 因此,让吸气者和安定者成为“未来防御”的一种方式,以适应稍后可能会发生的变化。

2.强化对象可以被操纵的手段。

获得者和制定者派上用场的另一个方法是强制对象可以被操纵的方式,因此对象是在控制自己的状态。 对象公开variables暴露出来,很容易被破坏。

例如, ImmutableArray对象包含一个名为myArrayint数组。 如果数组是一个公共字段,它将不会是不可变的:

 ImmutableArray a = new ImmutableArray(); int[] b = a.myArray; b[0] = 10; // Oops, the ImmutableArray a's contents have been changed. 

为了实现一个真正不可变的数组,应该写一个数组的getter( getArray方法),以便返回数组的副本:

 public int[] getArray() { return myArray.clone(); } 

即使发生以下情况:

 ImmutableArray a = new ImmutableArray(); int[] b = a.getArray(); b[0] = 10; // No problem, only the copy of the array is affected. 

ImmutableArray确实是不可变的。 暴露一个对象的variables将允许它以不是打算的方式被操作,但是只暴露某些方式(getter和setter),对象可以以预定的方式被操纵。

我认为让getter和setter对于那些将被别人使用的API的一部分来说更为重要,因为它允许保持API完好无损,同时允许底层实现的变化。

有了getter和setter的所有优点,如果getter只是返回私有variables的值而setter只是接受一个值并将其赋值给一个私有variables,那么getter和setter似乎是无关的,而且真的是一个浪费。 如果这个类仅仅被一个不会被别人使用的应用程序内部使用,那么使用getter和setter就可能不像编写一个公共API那么重要。

他们绝对是邪恶的。

@coobird不幸的是,他们绝对不会“强制封装的概念”,他们所做的一切就是让你认为你封装的数据实际上是通过一个属性暴露的方式暴躁的财产。 任何一个getter / setter做公共领域都会更好。

首先,如果你想公开数据,把它公开,摆脱getter&setter方法来减less客户端必须通过的方法的数量,并使其认知更简单,客户端通过例如改变它的值。

 object.field = value; 

而不是更认知的激烈

 object.setField(value); 

客户端现在必须检查getter / setter方法,看它是否有任何副作用。

其次,如果你真的需要在方法中做其他的事情,那么为什么把它称为一个get / set方法,当它有更多的责任而不是简单的获取或设置? 无论是按照SRP还是调用方法,实际上告诉你什么样的方法,像他提到的Zarkonnen的例子,例如。

 public void kill(){ isAlive = false; removeFromWorld(this); } 

代替

 public void setAlive(boolean isAlive){ this.isAlive = isAlive; if (isAlive) addToWorld(this); else removeFromWorld(this); } 

setAlive(boolean)方法在哪里告诉客户端,作为一个副作用,它将从世界中删除对象? 为什么客户应该对isAlive领域有所了解? 另外当对象被重新添加到世界中时会发生什么,是否应该重新初始化? 为什么客户会关心这些?

恕我直言,道德是命名方法来说明他们做什么,遵循SRP并摆脱getter / setters。 如果没有getter / setter的问题,告诉对象在自己的class级里做自己的肮脏的工作,而不是试图在其他class级与他们做事情。

在这里,我咆哮,对此感到抱歉;)

这是一个滑坡。

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

还有一类暴露一些“控制旋钮”的例子。 你的汽车收音机的用户界面可能被理解为暴露类似于getVolumesetVolumegetChannelsetChannel ,但它的真正function是接收信号并发出声音。 但是这些旋钮不会暴露太多的实现细节。 你不知道从这些接口function是否收音机是晶体pipe,主要是软件,或真空pipe。

你开始把对象看作问题领域任务的积极参与者越多,就越是要求它做某件事,而不是要求它告诉你它的内部状态,或者要求它其数据,所以其他代码可以做这些值的东西。

那么……“邪恶”? 不是真的。 但是,每当你倾向于放置一个价值,并且暴露出set价值方法,那么问自己为什么,那个对象的责任究竟是什么。 如果你能给自己的唯一答案是“为了保持这个价值”,那么也许除了面向对象之外的其他东西在这里。

如果它暴露了很多variables,那么你的游戏类可能跟在神对象反模式之后。 getter和setter没有任何问题(虽然他们在Java中的冗长可能有点烦人); 在一个devise良好的应用程序中,每个类都有一个清晰分离的function,在一个类中不需要几十个。

编辑:如果getters和setters的要点是“configuration”游戏类(我理解你的评论),那么你可能不需要getters(对于一个类来说,访问它自己的私有variables而不使用get方法),你也许可以将许多setter变成“group setter”,它们在概念上设置了几个variables。

我的观点是,获得者和制定者是优秀项目的要求。 坚持下去,但不要写不必要的getter / setters – 并不总是需要直接处理所有的variables。

吸气剂和吸附剂的存在往往表明(如果你是这种小学语言“气味”),有一个devise问题。 平凡的获得者和制定者与公共领域几乎没有区别。 通常,对数据进行操作的代码将处于不同的类别 – 封装不佳,以及程序员对OO不满意的程度。

在某些情况下,getter和setter是好的。 但是一般来说,同时具有getter和setter的types表示devise问题。 吸气者为不变而工作; 安装人员工作“告诉不要问”。 不变性和“不要问”是不错的deviseselect,只要它们不是重叠的。

我真的不认为他们是邪恶的。 但我很想生活在一个我从来没有用过的世界,除非我真的需要。

我上面看到的一个例子是future-proofing你的代码。 例如:

 public void setValue(int value) { this.value = value; } 

然后,需求会发生变化,您需要跟踪该值的设置次数。

所以:

 public void setValue(int value) { this.value = value; count++; } 

这很漂亮。 我知道了。 但是,在Ruby中,以下不会达到同样的目的吗?

 someobject.my_value = 100 

稍后,您需要跟踪my_value设置的次数。 那么,难道你不能只是重写setter 那么只有那么

 def my_value=(value) @my_value = value @count++ end 

我完全赞成漂亮的代码,但是我不得不承认,通过Java类的山脉,我们可以看到成千上万的代码行,但是基本的getter / setter却是丑陋而烦人的。

当我用C#开发全部时,我们一直使用公有属性,只在需要时才定制getters / setter。 像魅力一样工作,没有破坏任何东西。

与往常一样,唯一的答案是:这取决于。 如果你是唯一一个接触代码的人,你可以做任何你喜欢的事情,包括采取捷径。

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

你可能想要对这些方法实际得到和设定的内容给予更多的关注。 如果使用它们来提供对常量值的访问,那么使用常量可能会更好。

这取决于有问题的编程语言。 你的问题是在Java的背景下构build的,看起来getter和setter通常被认为是一件好事。

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

在Java中(至less是十年前我学习的Java版本),这是不可能的。 因此,在Java中,通常最好是使用getter和setter,这样如果需要的话,可以覆盖对variables的访问。

(这不会使Python比Java更好,只是不同而已。)

只是供参考:除了在这个线程中的所有优秀的答案,请记住,所有的原因,你可以拿出或反对获得者/ setters,性能不是一个(有些人可能会相信)。 JVM足够聪明,可以embedded微不足道的getter / setter(即使不是final的getter / setter,只要它们没有被覆盖)。

你可能想要用值类来replace你的一些类。 这将允许您删除吸气剂,并避免内容从您下面更改时的问题。

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

一般来说,你也应该发现,你需要比吸气者less得多的提供一个setter,特别是当你试图让你的对象不变时 – 这是一件好事(但并不总是最好的select) – 但即使不是这样。

我几个星期前一直在用java进行编程,而且我知道只有在应用程序需要的时候才应该使用getters&setter

玩的开心 :)