Что более уместно:геттеры и сеттеры или функции?
-
05-07-2019 - |
Вопрос
Стоит ли когда-нибудь отказываться от шаблонов геттеров и сеттеров «getMyValue()» и «setMyValue()», если альтернативные имена функций делают API более очевидным?
Например, представьте, что у меня есть этот класс на C++:
public class SomeClass {
private:
bool mIsVisible;
public:
void draw();
void erase();
}
Я мог бы добавить функции для получения/установки «mIsVisible» следующим образом:
bool getVisible() { return mIsVisible; };
void setvisible (bool visible) {if (! ошибочно && visible) {draw ();} else if (неправильно &&! visible) {eRase ();}
mIsVisible = visible;
}
Однако вместо этого в равной степени можно было бы использовать следующие методы:
bool isVisible() { return mIsVisible; };
void show() {
if (!mIsVisible) {
mIsVisible = true;
draw();
}
}
void hide() {
if (mIsVisible) {
mIsVisible = false;
erase();
}
}
Короче говоря, лучше ли иметь один метод «setVisible(bool)» или пару методов «show()» и «hide()»?Есть ли условность или это чисто субъективная вещь?
Решение
Прочитайте статью "Расскажи, не спрашивай" на веб-сайте Pragmatic Programmers, и я думаю, вы увидите, что второй пример - это то, что вам нужно.
По сути, вам не следует распространять логику через свой код, что подразумевается в вашем первом примере, а именно:
- получить текущее значение видимости,
- принимать решения, основываясь на ценности,
- обновить объект.
Другие советы
В приведенном вами примере show()
и hide()
имеют большой смысл, по крайней мере для меня.
С другой стороны, если бы у вас была собственность skinPigment
и вы решили создать функции с именем tanMe()
и makeAlbino()
это был бы действительно плохой и неочевидный выбор.
Это субъективно, вы должны стараться думать так, как думают ваши пользователи (люди, использующие этот класс).Какой бы путь вы ни выбрали, для них это должно быть очевидно, и хорошо документированы.
Я бы выбрал набор isVisible()/show()/hide().
setVisible() подразумевает, что все, что он делает, это меняет внутреннюю переменную.show() иide() проясняют побочные эффекты.
С другой стороны, если бы все getVisible()/setVisible() выполнили был чтобы изменить внутреннюю переменную, то вы совсем немного изменились по сравнению с тем, что они были общедоступными полями.
на самом деле сеттеры имеют мало общего с объектной ориентацией, которая является идиомой программирования, примененной в этом примере.геттеры немного лучше, но во многих случаях без них можно обойтись.Если все можно получить и установить, какой смысл иметь объект?Для выполнения каких-либо действий над объектами следует вызывать операции, изменение внутреннего состояния — всего лишь побочный эффект этого.Плохая сторона сеттера при наличии полиморфизма — одного из краеугольных камней объектно-ориентированного подхода — заключается в том, что вы заставляете каждый производный класс иметь сеттер.Что, если рассматриваемому объекту не нужно внутреннее состояние, называемое mIsVisible?Конечно, он может проигнорировать вызов и реализовать его как пустой, но тогда у вас останется бессмысленная операция.OTOH, такие операции, как отображение и скрытие, можно легко переопределить с помощью различных реализаций, ничего не раскрывая о внутреннем состоянии.
В общем, я думаю, что сеттеры/геттеры должны устанавливать только значения свойств.В вашем примере вы также выполняете действие на основе значения свойства isVisible.В этом случае я бы сказал, что использование функций для выполнения действия и обновления состояния лучше, чем использование метода установки/получания, который выполняет действие в качестве побочного эффекта обновления свойства.
Если переключение mIsVisible действительно немедленно включает и выключает видимость объекта, используйте сценарий показа/скрытия.Если он останется в старом состоянии еще немного (напр.пока что-то еще не вызовет перерисовку), тогда лучше всего использовать сценарий установки/получения.
Я предпочитаю методы show() и скрыть(), потому что они явно сообщают, что вы собираетесь делать.setVisible(boolean) не сообщает вам, будет ли метод отображаться/отрисовываться сразу.Плюс show() иide() — более удачные методы для интерфейса (ИМХО).
Неявно перечисленные вами функции «показать» и «скрыть» являются установщиками.
Я думаю, что для логических значений подойдет один инструмент, подобный показанному вами.Однако функции .show и .hide также выглядят как команды, а не как функции, изменяющие состояние объекта.
В случае, если вам действительно нужно написать код типа
if (shouldBeShowingAccordingToBusinessLogic()) w.show();
else w.hide();
повсюду, возможно, вам будет лучше с
w.showIfAndOnlyIf(shouldBeShowingAccordingToBusinessLogic())
Или, в действительно странных случаях, когда ваша логика не может решить, делать это или нет до конца некоторого фрагмента кода, вы можете попробовать
w.setPostponedVisibility(shouldBeShowingAccordingToBusinessLogic());
...
w.realizeVisibility();
(Разве я не говорил, что это странно?)
Дополнительная мотивация для решения отображения/скрытия заключается в том, что, будучи установщиком,
тот setVisible
метод имеет «побочный эффект», заключающийся в том, что он также отображает или скрывает SomeClass
.Методы отображения/скрытия лучше передают смысл происходящего.