Вопрос-ответ

Are getters and setters poor design? Contradictory advice seen [duplicate]

Плохой ли дизайн геттеров и установщиков? Замечен противоречивый совет

В настоящее время я работаю над простой игрой на Java с несколькими различными режимами. Я расширил класс main Game, чтобы поместить основную логику в другие классы. Несмотря на это, класс main game по-прежнему довольно увесистый.

После беглого просмотра моего кода выяснилось, что большая его часть состояла из геттеров и сеттеров (60%) по сравнению с остальным, что действительно необходимо для логики игры.

В нескольких поисковых системах Google утверждается, что геттеры и сеттеры - это зло, в то время как другие утверждают, что они необходимы для хорошей практики OO и отличных программ.

Итак, что мне делать? Каким это должно быть? Должен ли я менять свои геттеры и сеттеры для моих частных переменных или мне следует придерживаться их?

Переведено автоматически
Ответ 1

Существует также точка зрения, что в большинстве случаев использование сеттеров по-прежнему нарушает инкапсуляцию, позволяя вам устанавливать значения, которые не имеют смысла. В качестве очень очевидного примера, если у вас есть счетчик очков в игре, который постоянно увеличивается, вместо

// 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);

Возможно, это несколько поверхностный пример. Я пытаюсь сказать, что обсуждение геттеров / сеттеров в сравнении с общедоступными полями часто скрывает более серьезные проблемы с объектами, которые интимным образом манипулируют внутренним состоянием друг друга и, следовательно, слишком тесно связаны.

Идея состоит в том, чтобы создать методы, которые напрямую выполняют то, что вы хотите сделать. Примером может служить установка статуса "живой" для врагов. У вас может возникнуть соблазн использовать setAlive (логический активный метод). Вместо этого вы должны иметь:

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

  • Очень зло: общедоступные поля.

  • Несколько злые: геттеры и сеттеры там, где они не требуются.

  • Хорошо: геттеры и сеттеры только там, где они действительно требуются - заставляют тип демонстрировать "большее" поведение, которое происходит с использованием его состояния, вместо того, чтобы просто рассматривать тип как хранилище состояния, которым манипулируют другие типы.

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

Ответ 3

You've already had a lot of good answers on this, so I'll just give my two cents. Getters and setters are very, very evil. They essentially let you pretend to hide your object's internals when most of the time all you've done is tossed in redundant code that does nothing to hide internal state. For a simple POJO, there's no reason why getName() and setName() can't be replaced with obj.name = "Tom".

If the method call merely replaces assignment, then all you've gained by preferring the method call is code bloat. Unfortunately, the language has enshrined the use of getters and setters in the JavaBeans specification, so Java programmers are forced to use them, even when doing so makes no sense whatsoever.

Fortunately, Eclipse (and probably other IDEs as well) lets you automatically generate them. And for a fun project, I once built a code-generator for them in XSLT. But if there's one thing I'd get rid of in Java, its the over-dependence on getters and setters.

Ответ 4

Getters and setters enforce the concept of encapsulation in object-oriented programming.

By having the states of the object hidden from the outside world, the object is truly in charge of itself, and cannot be altered in ways that aren't intended. The only ways the object can be manipulated are through exposed public methods, such as getters and setters.

There are a few advantages for having getters and setters:

1. Allowing future changes without modification to code that uses the modified class.

One of the big advantage of using a getter and setter is that once the public methods are defined and there comes a time when the underlying implementation needs to be changed (e.g. finding a bug that needs to be fixed, using a different algorithm for improving performance, etc.), by having the getters and setters be the only way to manipulate the object, it will allow existing code to not break, and work as expected even after the change.

For example, let's say there's a setValue method which sets the value private variable in an object:

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

But then, there was a new requirement which needed to keep track of the number of times value was changed. With the setter in place, the change is fairly trivial:

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

If the value field were public, there is no easy way to come back later and add a counter that keeps track of the number of times the value was changed. Therefore, having getters and setters are one way to "future-proof" the class for changes which may come later.

2. Enforcing the means by which the object can be manipulated.

Another way getters and setters come in handy is to enforce the ways the object can be manipulated, therefore, the object is in control of its own state. With public variables of an object exposed, it can easily be corrupted.

For example, an ImmutableArray object contains an int array called myArray. If the array were a public field, it just won't be immutable:

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

To implement a truly immutable array, a getter for the array (getArray method) should be written so it returns a copy of its array:

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

And even if the following occurs:

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

The ImmutableArray is indeed immutable. Exposing the variables of an object will allow it to be manipulated in ways which aren't intended, but only exposing certain ways (getters and setters), the object can be manipulated in intended ways.

I suppose having getters and setters would be more important for classes which are part of an API that is going to be used by others, as it allows keeping the API intact and unchanged while allowing changes in the underlying implementation.

With all the advantages of getters and setters said, if the getter is merely returning the value of the private variable and the setter is merely accepting a value and assigning it to a private variable, it seems the getters and setter are just extraneous and really a waste. If the class is going to be just for internal use by an application that is not going to be used by others, using getters and setters extensively may not be as important as when writing a public API.

java oop