Java 吸球手和接球手的设计差吗?矛盾的建议

Java 吸球手和接球手的设计差吗?矛盾的建议,java,oop,setter,getter,accessor,Java,Oop,Setter,Getter,Accessor,我目前正在用Java开发一个简单的游戏,有几种不同的模式。我扩展了一个主游戏类,将主逻辑放在其他类中。尽管如此,主要的游戏类仍然相当强大 在快速查看我的代码后,大多数代码是getter和setter(60%),而其余代码是游戏逻辑真正需要的 一些谷歌搜索声称getter和setter是邪恶的,而另一些则声称它们对于良好的OO实践和伟大的程序是必要的 那我该怎么办?应该是哪一个?我应该为我的私有变量更改getter和setter,还是应该坚持使用它们? 非常邪恶:公共领域 有些邪恶:在不需要它们的

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

在快速查看我的代码后,大多数代码是getter和setter(60%),而其余代码是游戏逻辑真正需要的

一些谷歌搜索声称getter和setter是邪恶的,而另一些则声称它们对于良好的OO实践和伟大的程序是必要的

那我该怎么办?应该是哪一个?我应该为我的私有变量更改getter和setter,还是应该坚持使用它们?

  • 非常邪恶:公共领域
  • 有些邪恶:在不需要它们的地方使用getter和setter
  • 好:getter和setter只在真正需要它们的地方使用——使类型暴露碰巧使用其状态的“更大”行为,而不是仅仅将该类型视为其他类型操作的状态存储库

不过,这取决于具体情况——有时你真的只需要一个哑数据对象。

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

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

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

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


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

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


一般来说,您还应该发现,与getter相比,您需要提供setter的次数要少得多,尤其是当您试图使对象不可变时,这是一件好事(但并不总是最佳选择),但即使不是这样。

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


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

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

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

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


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

getter和setter的出现往往表明(如果你对那种小学语言感兴趣,那就是一种“气味”)这是一个设计问题。琐碎的getter和setter与公共字段几乎没有区别。通常,在数据上操作的代码将处于不同的类中-封装性差,并且您希望程序员不太容易使用OO


在某些情况下,getter和setter是可以使用的。但是作为一种规则,同时包含getter和setter的类型表示设计问题。getter用于实现不变性;setter用于实现“告诉-不要问”。不变性和“告诉-不要问”“是很好的设计选择,只要它们不以重叠的方式应用。

仅供参考:除了本主题中的所有优秀答案外,请记住,在所有支持或反对getter/setter的原因中,性能不是一个(正如一些人可能相信的那样)。JVM足够聪明,可以内联琐碎的getter/setter(即使是非最终的getter/setter,只要它们实际上没有被覆盖)。

这是一个滑铁卢

简单传输对象(或参数对象)的唯一目的可能是保存某些字段并根据需要提供其值。然而,即使在这种退化的情况下,人们也可能认为对象应该是不可变的——在构造函数中配置,并且只公开
get
。。。方法

还有一个类公开了一些“控制旋钮”;您的车载收音机的用户界面可能可以理解为公开一些东西,如
getVolume
setVolume
getChannel
、和
setChannel
,但其真正的功能是接收信号和发出声音。但这些旋钮并没有暴露太多的实现细节;从这些接口特性中,你不知道收音机是晶体管,主要是软件,还是真空管

你开始想得越多
// 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);
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; }
public void setValue(int value)
{
    this.value = value;
}
public void setValue(int value)
{
    this.value = value;
    count++;
}
ImmutableArray a = new ImmutableArray();
int[] b = a.myArray;
b[0] = 10;      // Oops, the ImmutableArray a's contents have been changed.
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.
object.field = value;
object.setField(value);
public void kill(){
    isAlive = false;
    removeFromWorld(this);
}
public void setAlive(boolean isAlive){
    this.isAlive = isAlive;
    if (isAlive)
        addToWorld(this);
    else
        removeFromWorld(this);
}
public void setValue(int value)
{
    this.value = value;
}
public void setValue(int value)
{
    this.value = value;
    count++;
}
someobject.my_value = 100
def my_value=(value)
    @my_value = value
    @count++
end