Инструкции по Использованию Интерфейса Java — Являются методами get и методами set в интерфейсе плохо?

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

Для запуска я должен представить понятие пространства имен. При вводе команды в интерпретатор Схемы это должно оценить различные символы в выражении и получить их значение. Пример:

(define x 3)

(define y 4)

(+ x y) returns 7

определить выражения хранят значение 3 в месте для x и значения 4 в месте для y. Тогда, когда мы звоним (+ x y), интерпретатор ищет значения в пространстве имен и в состоянии выполнить операцию и возвратиться 7.

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

(define x 3)

(define y 4)

(let ((x 5))
   (+ x y)) returns 9

x returns 3

то, Что, делает ключевое слово, которому позволяют, начинает новое пространство имен с x как значение 5. Вы заметите, что это все еще в состоянии видеть, что y равняется 4, делая сумму возвращенной, чтобы быть 9. Можно также видеть, что, как только выражение закончилось, x вернулся к тому, чтобы быть 3. В этом смысле x был временно замаскирован локальным значением.

Процедурные и объектно-ориентированные языки имеют подобное понятие. Каждый раз, когда Вы объявляете переменную в функции, которая имеет то же имя как глобальная переменная, Вы получаете тот же эффект.

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

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

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns ?

Мы определяем x, чтобы быть 3 и плюс - x, чтобы быть его параметром, y, плюс значение x. Наконец мы звоним плюс - x в среде, где x был замаскирован новым x, этими ценными 5. Если мы просто храним операцию, (+ x y), для функции плюс - x, так как мы находимся в контексте x быть 5, возвращенный результат был бы 9. Это - то, что назвало динамический обзор.

Однако Схема, язык Common LISP и много других языков имеют то, что назвало лексический обзор - в дополнение к хранению операции (+ x y) мы также храним пространство имен в той конкретной точке. Тот путь, когда мы ищем значения, мы видим, что x, в этом контексте, равняется действительно 3. Это - закрытие.

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns 7

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

35
задан oxbow_lakes 15 July 2009 в 10:27
поделиться

11 ответов

Я думаю, что существует два типа интерфейсов, объявленных в целом:

  1. описание службы . Это может быть что-то вроде CalculationService . Я не думаю, что методы getX должны быть в таком интерфейсе, и определенно не setX . Они совершенно ясно подразумевают детали реализации, которые не являются задачей этого типа интерфейса.
  2. модель данных - существует исключительно для абстрагирования реализации объектов данных в системе. Они могут быть использованы для помощи в тестировании или просто потому, что некоторые люди такого же возраста, как я, помнят дни, когда (например) использование фреймворка персистентности связывало вас с определенным суперклассом (т.е. вы бы выбрали реализацию интерфейса в случае, если вы переключили свой уровень сохраняемости). Я думаю, что наличие методов JavaBean в этом типе интерфейса вполне разумно.

Примечание: классы коллекций, вероятно, соответствуют типу № 2

13
ответ дан 27 November 2019 в 07:12
поделиться

Я не понимаю, почему интерфейс не может определять геттеры и сеттеры. Например, List.size () фактически является геттером. Интерфейс должен определять поведение, а не реализацию , хотя - он не может сказать, как вы обработаете состояние, но он может настаивать на том, чтобы вы могли его получить и установить.

Интерфейсы коллекций, например, связаны с состоянием, но разные коллекции могут хранить это состояние радикально по-разному.

РЕДАКТИРОВАТЬ: комментарии предполагают, что геттеры и сеттеры подразумевают, что для резервного хранилища используется простое поле. Я категорически не согласен с этим утверждением. На мой взгляд, подразумевается, что «достаточно дешево» получить / установить значение, но не то, что оно хранится как поле с тривиальной реализацией.


РЕДАКТИРОВАТЬ: Как отмечено в комментариях, это явно указано в Спецификация JavaBeans раздел 7.1:

Таким образом, даже когда автор сценария набирает в чем-то вроде b.Label = foo все еще есть вызов метода в целевой объект для установки свойства, и целевой объект имеет полный программное управление.

Таким образом, свойства не должны быть простыми поля данных, они могут быть вычисленные значения. Обновления могут иметь различные программные побочные эффекты. За пример, изменение фона бина свойство цвета также может вызвать боб перекрасить на новый цвет. "


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

Например, рассмотрим компонент с

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
}

Или (желательно IMO):

private Size size;

public int getWidth() {
    return size.getWidth();
}

public int getHeight() {
    return size.getHeight();
}

public Size getSize() {
    return size;
}

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

24
ответ дан 27 November 2019 в 07:12
поделиться

Я вообще не думаю, что у bean-компонента должен быть интерфейс поверх него. Javabean - это интерфейс в более общем смысле. Интерфейс определяет внешний контракт чего-то более сложного. Внешний контракт javabean'а и его внутреннее представление идентичны.

Я бы не сказал, что у вас не должно быть геттеров в интерфейсе. Имеет смысл иметь интерфейс ReadableDataThingie, который реализуется DataThingieBean.

4
ответ дан 27 November 2019 в 07:12
поделиться

В геттерах / сеттерах по сути нет ничего плохого. Однако:

  1. Я стараюсь сделать свои объекты неизменяемыми (в первую очередь) по отношению к содержащимся в них полям. Почему ? Большинство вещей я создаю на этапе строительства. Если я хочу что-то изменить позже, я снимаю эти ограничения. Так что мои интерфейсы будут содержать геттеры, но не сеттеры (есть и другие преимущества - в частности, многопоточность).
  2. Я хочу, чтобы мои объекты делали что-то за меня , а не наоборот. Поэтому, когда один из моих объектов получает несколько геттеров, я начинаю спрашивать, должен ли этот объект иметь больше функциональных возможностей вместо того, чтобы предоставлять все свои данные для чего-то другого, с чем можно работать. См. этот ответ для более подробной информации.

Это все рекомендации, примечание.

10
ответ дан 27 November 2019 в 07:12
поделиться

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

Я предпочитаю не иметь средств доступа в интерфейсе, а добавлять участников с помощью аргументов конструктора в реализацию.

1
ответ дан 27 November 2019 в 07:12
поделиться

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

1
ответ дан 27 November 2019 в 07:12
поделиться

Для дальнейшего чтения: Практическое признание дизайна API архитектора Java Framework (Ярослав Тулач, 2008, Apress).

0
ответ дан 27 November 2019 в 07:12
поделиться

Я использовал такие интерфейсы, например, у нас были классы с полями beginDate, endDate. Эти поля были во многих классах, и у меня был один вариант использования, когда мне нужно было получить эти даты для разных объектов, поэтому я извлек интерфейс и был очень счастлив :)

0
ответ дан 27 November 2019 в 07:12
поделиться

Обычно, если ответ на вопрос «Нужно ли мне знать значение [state, property, AnyThignAMaGit], чтобы работать с его экземпляром?» тогда да ... аксессоры принадлежат интерфейсу.

List.size () от Джона выше - прекрасный пример геттера, который должен быть определен в интерфейсе

0
ответ дан 27 November 2019 в 07:12
поделиться

Геттеры используются для запроса состояния объекта - что вы действительно можете избегайте при разработке интерфейса. Прочтите http://www.pragprog.com/articles/tell-dont-ask

0
ответ дан 27 November 2019 в 07:12
поделиться

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

Для начала, по крайней мере, с Java и исключая объявления Exception, вы не можете определить полное поведение без состояния. В Java интерфейсы не определяют поведение. Они не могут. Они определяют типы; обещания реализации набора сигнатур функций, возможно, с некоторыми исключениями пост-условий. Но это все. Поведение и состояние определяются классами, реализующими эти интерфейсы.

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

Учитывая это, нет ничего плохого - синтаксически и семантически - в наличии сеттеров и геттеров в интерфейсах.

Если ваше приложение хорошо смоделировано и проблема требует наличия интерфейса, определяющего сеттеры и геттеры, почему бы и нет. Например, взгляните на интерфейс ServletResponse.

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

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

Надеюсь, это поможет.

2
ответ дан 27 November 2019 в 07:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: