Являются ли геттеры и сеттеры плохим дизайном? Противоречивые советы видел [дубликат]


этот вопрос уже есть ответ здесь:

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

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

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

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

16 219

16 ответов:

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

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

он должен быть!--5-->

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

Это, пожалуй, немного поверхностный пример. Я пытаюсь сказать, что обсуждение getter / setters vs public fields часто скрывает большие проблемы с объектами манипулируя внутренним состоянием друг друга в интимной манере и, следовательно, будучи слишком тесно связаны.

идея состоит в том, чтобы сделать методы, которые непосредственно делают то, что вы хотите сделать. Примером может служить то, как установить "живой" статус врагов. Вы могли быть уговорены для того чтобы иметь 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; }
  • очень зло: публичные поля.
  • несколько зло: геттеры и сеттеры, где они не требуются.
  • хорошо: геттеры и сеттеры только там, где они действительно необходимы - сделайте тип "большим" поведением, которое происходит с использовать его состояние, а не просто обработка типа как репозитория состояния для управления другими типами.

это действительно зависит от ситуации - иногда действительно do просто хочу тупой объект данных.

У вас уже было много хороших ответов на этот вопрос, поэтому я просто дам свои два цента. Геттеры и сеттеры очень, очень злые. Они по существу позволяют вам притворяться, что скрывают внутренние части вашего объекта, когда большую часть времени все, что вы сделали, бросается в избыточный код, который ничего не делает, чтобы скрыть внутреннее состояние. Для простого POJO нет причин, по которым getName() и setName() не могут быть заменены obj.name = "Томь".

Если вызов метода просто заменяет назначение, то все у вас полученный путем предпочтения вызова метода-это раздувание кода. К сожалению, язык закрепил использование геттеров и сеттеров в спецификации JavaBeans, поэтому программисты Java вынуждены использовать их, даже когда это не имеет никакого смысла.

к счастью, Eclipse (и, вероятно, другие IDE) позволяет автоматически генерировать их. И для забавного проекта я однажды построил для них генератор кода в XSLT. Но если есть одна вещь, от которой я бы избавился на Java, это чрезмерная зависимость от геттеров и сеттеров.

геттеры и сеттеры применить концепцию инкапсуляция в объектно-ориентированном программировании.

есть несколько преимуществ для геттеров и сеттеры:

1. Разрешение будущих изменений без изменения кода, который использует измененный класс.

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

например, предположим, что есть setValue метод, который устанавливает value частная переменная в объекте:

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

но тогда было новое требование, которое нужно было отслеживать количество раз . С сеттером на месте, изменение довольно тривиально:

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

если value поле было публичным, нет простого способ вернуться позже и добавить счетчик, который отслеживает количество раз, когда значение было изменено. Поэтому наличие геттеров и сеттеров является одним из способов "будущего доказательства" класса для изменений, которые могут произойти позже.

2. Применение средств, с помощью которых можно манипулировать объектом.

еще один способ геттеров и сеттеров пригодится, чтобы обеспечить способы, которыми объект можно манипулировать, поэтому объект контролирует свое собственное состояние. С открытые переменные объекта, он может быть легко поврежден.

например,

они абсолютно злы.

@coobird к сожалению, они абсолютно не" применяют концепцию инкапсуляции", все, что они делают, это заставляют вас думать, что вы инкапсулируете данные, когда на самом деле вы подвергаете данные через свойство с заблуждением величия метода. Все, что геттер / сеттер делает публичное поле, делает лучше.

во-первых, если вы хотите общедоступные данные, сделайте их общедоступными, избавьтесь от методов getter & setter, чтобы уменьшить количество методов, которые клиент должен пробираться и познавательно проще для клиента, чтобы изменить его значение, например.

object.field = value;

вместо более интенсивной когнитивно

object.setField(value);

где клиент должен теперь проверить метод getter / setter, чтобы увидеть, если он имеет какие-либо побочные эффекты.

во-вторых, если вам действительно нужно сделать что-то еще в методе, зачем называть его методом get/set, когда у него больше обязанностей, чем просто получение или настройка? Либо следуйте SRP, либо вызовите метод что-то что на самом деле говорит вам, что весь метод действительно любит примеры Зарконнена, которые он упомянул, например.

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 и избавиться от геттеров/сеттеров. Если есть проблемы без геттеров / сеттеров, скажите объектам делать свою собственную грязную работу внутри своего собственного класса вместо того, чтобы пытаться делать что-то с ними в других классах.

здесь заканчивается моя тирада, извините за это;)

это скользкий путь.

простой объект передачи (или объект параметра) может иметь единственную цель хранения некоторых полей и предоставления их значений по требованию. Однако даже в этом вырожденном случае можно утверждать, что объект должен быть неизменяемым -- настроен в конструкторе и предоставляет только get... методы.

есть также случай класса, который предоставляет некоторые "ручки управления"; пользовательский интерфейс вашего автомобильного радио, вероятно, можно понять как разоблачение что-то вроде getVolume,setVolume,getChannel и setChannel, но его реальная функциональность-прием сигналов и излучение звука. Но эти ручки не раскрывают много деталей реализации; вы не знаете из этих функций интерфейса, является ли радио транзисторами, в основном программным обеспечением или вакуумными лампами.

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

так... "зло"? Не реально. Но каждый раз, когда вы склонны вставлять значение и выставлять оба get... и set... методы по этому значению, спросите себя, почему и что такое ответная способность этого объекта на самом деле. Если единственный ответ, который вы можете дать себе, это "держать это значение для меня", то может быть что-то кроме ОО идем дальше.

ваш игровой класс, вероятно, следует за Бог объект антипаттерн, если он предоставляет так много переменных. Нет ничего плохого в геттерах и сеттерах (хотя их многословие в Java может быть немного раздражающим); в хорошо разработанном приложении, где каждый класс имеет четко разделенную функциональность, вам не понадобятся десятки из них в одном классе.

Edit: если главным моментом для геттеров и сеттеров является "настройка" класса игры (я понимаю ваш комментарий таким образом), то вам, вероятно, не нужны геттеры (это совершенно нормально для класса, чтобы получить доступ к своим собственным частным переменным без использования методов get), и вы, вероятно, можете свернуть многие из сеттеров в "групповые сеттеры", которые устанавливают несколько переменных, которые концептуально принадлежат друг другу.

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

наличие геттера и сеттеров имеет тенденцию указывать ("запах", если вы находитесь в таком языке начальной школы), что существует проблема дизайна. Тривиальные геттеры и сеттеры едва различимы от публичных полей. Обычно код, работающий с данными, будет иметь инкапсуляцию с другим классом, и то, что вы ожидаете от программистов, не будет легко с OO.

в некоторых случаях геттеры и сеттеры-это хорошо. Но как правило тип с обоими геттерами и сеттеры указывают на проблемы проектирования. Геттеры работают для неизменности; сеттеры работают для "скажи Не спрашивай". Как неизменность, так и" скажите Не спрашивайте " - это хороший выбор дизайна, если они не применяются в перекрывающемся стиле.

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

один пример, который я читал выше 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 был установлен. Ну тогда, не могли бы вы просто переопределить сеттер затем и только затем?

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

Я все для красивого кода, но я должен признать, глядя через горы классов Java у нас есть и видя буквально тысячи и тысячи строк кода, которые не что иное, как основные геттер/сеттеры уродливо и раздражает.

когда я был разработки на C# полный рабочий день, мы использовали общедоступные свойства все время и делали заказ геттеры/сеттеры только при необходимости. Сработало как заклинание и ничего не сломало.

Как всегда единственный ответ: это зависит. Если вы единственный Перон, прикасающийся к коду, вы можете делать все, что вам удобно, включая ярлыки.

одним из преимуществ использования сеттеров является то, что проверки должны проводиться только в одном месте в коде.

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

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

напротив, в мире Python они обычно считаются плохим стилем: они добавляют строки в код без фактического добавления функциональности. Когда программисты Python должны, они могут использовать метапрограммирование, чтобы поймать получение и / или установку атрибутов объекта.

В Java (по крайней мере, версия Java, которую я узнал немного десять лет назад), это было невозможно. Таким образом, в Java обычно лучше всего использовать геттеры и сеттеры религиозно, так что, если вам нужно, вы можете переопределить доступ к переменным.

(Это не делает Python обязательно лучше, чем Java, просто отличается.)

просто FYI: в дополнение ко всем отличным ответам в этой теме, помните, что из всех причин, которые вы можете придумать для или против геттеров/сеттеров, производительность не одна (как некоторые могут подумать). JVM достаточно умен, чтобы встроить тривиальные геттеры / сеттеры (даже не -final те, пока они на самом деле не переопределены).

вы можете заменить некоторые из ваших классов по классам. Это позволит вам удалить геттер и избежать проблем при изменении содержимого из-под тебя.

Если вам нужен внешний доступ к отдельным значениям полей, использовать геттеры и/ или сеттеры. Если нет, то никогда не используйте открытые поля. Все так просто! (Хорошо, это никогда что просто, но это хорошее эмпирическое правило).

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

я программировал на java несколько месяцев назад, и я узнал, что мы должны использовать getters & setters только тогда, когда это необходимо для приложения

удачи :)