Рекомендации по использованию интерфейса Java - Являются ли геттеры и сеттеры в интерфейсе плохими?
Что люди думают о лучших рекомендациях для интерфейса? Что должно и не должно входить в интерфейс?
Я слышал, как люди говорят, что, как правило, интерфейс должен определять только поведение, а не состояние. Означает ли это, что интерфейс не должен содержать геттеров и сеттеров?
Мое мнение: Может быть, не так для сеттеров, но иногда я думаю, что геттеры действительны для размещения в интерфейсе. Это просто для того, чтобы принудительно реализовать классы реализации для реализации этих методов получения и, таким образом, указать, что клиенты могут вызывать эти методы получения, например, для проверки чего-либо.
11 ответов
Я думаю, что есть два типа интерфейсов, заявленных в целом:
- описание услуги. Это может быть что-то вроде
CalculationService
, Я не думаю, что методыgetX
должен быть в таком интерфейсе, и, конечно, нетsetX
, Они довольно четко подразумевают детали реализации, что не является задачей этого типа интерфейса. - модель данных - существует исключительно для абстрагирования от реализации объектов данных в системе. Они могут быть использованы для помощи в тестировании или просто потому, что некоторые люди, такие же старые, как я, помнят дни, когда (например) использование персистентной среды связывало вас с определенным суперклассом (то есть вы решили реализовать интерфейс в случае, если вы переключились ваш постоянный слой). Я думаю, что наличие методов JavaBean в интерфейсе этого типа вполне разумно.
Примечание: классы коллекций, вероятно, вписываются в тип #2
Я не понимаю, почему интерфейс не может определять геттеры и сеттеры. Например, List.size()
эффективно добытчик. Интерфейс должен определять поведение, а не реализацию - хотя он не может сказать, как вы будете обрабатывать состояние, но он может настаивать на том, чтобы вы могли его получить и установить.
Например, все интерфейсы коллекций связаны с состоянием, но разные коллекции могут хранить это состояние радикально по-разному.
РЕДАКТИРОВАТЬ: комментарии предполагают, что геттеры и сеттеры подразумевают простое поле используется для резервного хранения. Я категорически не согласен с этим подтекстом. На мой взгляд, подразумевается, что получить / установить значение "достаточно дешево", но не то, что оно хранится как поле с тривиальной реализацией.
РЕДАКТИРОВАТЬ: Как отмечено в комментариях, это делается явным образом в разделе 7.1 спецификации JavaBeans:
Таким образом, даже когда автор сценария печатает что-то вроде
b.Label = foo
в целевом объекте все еще есть вызов метода для установки свойства, и целевой объект имеет полный программный контроль.Таким образом, свойства не должны быть просто полями данных, они могут быть фактически вычисленными значениями. Обновления могут иметь различные программные побочные эффекты. Например, изменение свойства цвета фона bean-компонента также может привести к перекрашиванию bean-компонента новым цветом."
Если бы предполагаемое следствие было правдой, мы могли бы точно так же выставить свойства как поля напрямую. К счастью, это не имеет смысла: геттеры и сеттеры имеют полное право на вычисления.
Например, рассмотрим компонент с
getWidth()
getHeight()
getSize()
Верите ли вы, что есть три переменных? Разве не разумно иметь:
private int width;
private int height;
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Size getSize() {
return new Size(width, height); // Assuming an immutable Size type
}
Или (желательно ИМО):
private Size size;
public int getWidth() {
return size.getWidth();
}
public int getHeight() {
return size.getHeight();
}
public Size getSize() {
return size;
}
Здесь либо свойство размера, либо свойства высоты / ширины предназначены только для удобства, но я не вижу, что это делает их недействительными в любом случае.
Нет ничего изначально злого в геттерах / сеттерах. Тем не мение:
- Я стремлюсь сделать мои объекты неизменяемыми (в первую очередь) относительно полей, которые они содержат. Зачем? Я создаю большинство вещей на этапе строительства. Если я хочу что-то изменить позже, я ослабляю эти ограничения. Таким образом, мои интерфейсы будут содержать геттеры, но не сеттеры (есть и другие преимущества - особенно многопоточность).
- Я хочу, чтобы мои объекты делали что-то для меня, а не наоборот. Поэтому, когда один из моих объектов получает несколько геттеров, я начинаю спрашивать, должен ли этот объект обладать большей функциональностью, вместо того, чтобы выставлять все свои данные для чего-то еще, с чем можно работать. Смотрите этот ответ для более подробной информации.
Это все рекомендации, обратите внимание.
Я не думаю, что бин должен иметь интерфейс поверх него, в общем. Javabean - это интерфейс в более общем смысле. Интерфейс определяет внешний контракт чего-то более сложного. Внешний контракт Javabean и его внутреннее представление идентичны.
Я бы не сказал, что у вас не должно быть геттеров в интерфейсе. Имеет смысл иметь интерфейс ReadableDataThingie, который реализуется DataThingieBean.
Я слышал, как люди говорят, что, как правило, интерфейс должен определять только поведение, а не состояние. Означает ли это, что интерфейс не должен содержать геттеров и сеттеров?
Для начинающих, по крайней мере с Java и без исключений, вы не можете определить полное поведение без состояния. В Java интерфейсы не определяют поведение. Они не могут. Что они определяют, так это типы; обещания реализации набора сигнатур признаков, возможно, с некоторыми постусловиями без исключений. Но это все. Поведение и состояние определяются классами, реализующими эти интерфейсы.
Во-вторых, если геттеры и сеттеры определены в интерфейсе, они на самом деле не определяют полное поведение (кроме того, что оно предназначено для чтения, а другое для записи по свойству.) Вы можете иметь сложное поведение за сеттерами и геттерами, но они могут быть реализованным только в реальных классах. В языке Java нет ничего, что могло бы позволить нам свободно определять поведение в интерфейсах, за исключением самых ограниченных случаев.
Учитывая это, нет ничего плохого - синтаксически и семантически - в том, что в интерфейсах есть сеттеры и геттеры.
Если ваше приложение хорошо смоделировано и проблема требует наличия интерфейса, определяющего сеттеры и геттеры, почему бы и нет. Например, взгляните на интерфейс ServletResponse.
Теперь, если мы рассмотрим методы получения и установки с точки зрения реализации классов, совместимых со спецификациями JavaBeans, вам не нужно определять интерфейсы для них.
Но если у вас есть вещи, для которых требуются сеттеры и геттеры, как, например, bean-компонент, и которые также необходимо подключать при компиляции (а не во время выполнения, как может быть bean-компонент), и для которых может существовать несколько реализаций, тогда да, это вызвало бы интерфейс, определяющий методы получения и установки.
Надеюсь, поможет.
Это касается всей темы "Getter/Setters" - злая тема, которая неоднократно рассматривается на этом сайте и в других местах.
Я предпочитаю не иметь средства доступа в интерфейсе, а добавлять коллабораторов, использующих аргументы конструктора, к реализации.
Тот факт, что прямая реализация чего-либо заключается в получении, не должен останавливать его нахождение в интерфейсе, если это необходимо.
Я использовал такие интерфейсы, например, у нас были классы с полями beginDate, endDate. Эти поля были во многих классах, и у меня был один вариант использования, мне нужно было получить эти даты для разных объектов, поэтому я извлек интерфейс и был очень доволен:)
Геттеры используются для запроса состояния объекта - которого вы действительно можете избежать при разработке вашего интерфейса. Читайте http://www.pragprog.com/articles/tell-dont-ask
В основном, если ответ "Нужно ли знать значение [state, property, whatThignAMaGit] для работы с его экземпляром?" тогда да... средства доступа принадлежат интерфейсу.
List.size () от Джона выше - отличный пример геттера, который должен быть определен в интерфейсе
Для дальнейшего чтения: Практические API Признания в дизайне Java Framework Architect (Ярослав Тулач, 2008, Apress).