Это полностью противоречит способу Java создавать объекты, подобные структуре?
class SomeData1 {
public int x;
public int y;
}
Я вижу класс с аксессорами и мутаторами, более похожими на Java.
class SomeData2 {
int getX();
void setX(int x);
int getY();
void setY(int y);
private int x;
private int y;
}
Класс из первого примера удобен для обозначения.
// a function in a class
public int f(SomeData1 d) {
return (3 * d.x) / d.y;
}
Это не так удобно.
// a function in a class
public int f(SomeData2 d) {
return (3 * d.getX()) / d.getY();
}
Ответы:
Это часто обсуждаемая тема. Недостаток создания открытых полей в объектах заключается в том, что вы не можете контролировать значения, которые для него установлены. В групповых проектах, где много программистов используют один и тот же код, важно избегать побочных эффектов. Кроме того, иногда лучше возвращать копию объекта поля или каким-либо образом трансформировать его и т. Д. Вы можете высмеивать такие методы в своих тестах. Если вы создадите новый класс, вы можете не увидеть все возможные действия. Это похоже на защитное программирование - когда-нибудь получатели и установщики могут оказаться полезными, и их создание / использование не требует больших затрат. Поэтому они иногда полезны.
На практике большинство полей имеют простые методы получения и установки. Возможное решение будет выглядеть так:
Обновление: маловероятно, что поддержка свойств будет добавлена в Java 7 или, возможно, когда-либо. Другие языки JVM, такие как Groovy, Scala и т. Д., Поддерживают эту функцию сейчас. - Алекс Миллер
источник
=
, что, на мой взгляд, делает код чище.x
две разные вещи, не делает это хорошей идеей. ИМХО, это плохое предположение, поскольку оно может привести к путанице среди читателей. Основной принцип: не заставляйте читателя делать двойной дубль; сделайте очевидным то, что вы говорите - используйте разные имена для разных сущностей. Даже если разница заключается только в том, чтобы добавить подчеркивание. Не полагайтесь на пунктуацию, чтобы различать объекты.Похоже, что многие Java-люди не знакомы с Sun Java Coding Guidelines, в которых говорится, что вполне целесообразно использовать общедоступную переменную экземпляра, когда класс по сути является «Struct», если Java поддерживает «struct» (когда нет поведения).
Люди склонны думать, что геттеры и сеттеры - это способ Java, как будто они лежат в основе Java. Это не так. Если вы следуете руководству Sun Java Coding Guidelines, используя общедоступные переменные экземпляра в соответствующих ситуациях, вы на самом деле пишете лучший код, чем загромождаете его ненужными средствами получения и установки.
Соглашения Java Code от 1999 и до сих пор без изменений.
10.1 Предоставление доступа к переменным экземпляра и класса
Не делайте ни один экземпляр или переменную класса общедоступным без уважительной причины. Часто переменные экземпляра не нужно явно устанавливать или получать часто, что происходит как побочный эффект вызовов методов.
Одним из примеров соответствующих общедоступных переменных экземпляра является случай, когда класс по сути является структурой данных без какого-либо поведения. Другими словами, если бы вы использовали структуру вместо класса (если Java поддерживает структуру), то целесообразно сделать переменные экземпляра класса общедоступными .
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
источник
Используйте здравый смысл на самом деле. Если у вас есть что-то вроде:
Тогда нет смысла заключать их в геттеры и сеттеры. Вы никогда не будете хранить координаты x, y в целых пикселях другим способом. Геттеры и сеттеры только замедляют вас.
С другой стороны, с:
Возможно, вы захотите изменить способ расчета баланса в какой-то момент в будущем. Это должно действительно использовать геттеры и сеттеры.
Всегда лучше знать, почему вы применяете хорошую практику, чтобы вы знали, когда можно нарушать правила.
источник
(-5, -5)
не был хорошая идея. :-)Для решения проблем изменчивости вы можете объявить x и y как final. Например:
Вызывающий код, который пытается записать в эти поля, получит ошибку времени компиляции: «поле x объявлено окончательным; его нельзя назначить».
В этом случае код клиента может иметь удобство «быстрого доступа», которое вы описали в своем посте.
источник
case
выражении, ссылающемся на такое поле экземпляра, я получилCase expressions must be constant expressions
. как обойти это? какая здесь идиоматическая концепция?Не используй
public
поляНе используйте
public
поля, если вы действительно хотите обернуть внутреннее поведение класса. Взятьjava.io.BufferedReader
к примеру. Имеет следующее поле:skipLF
читается и пишется во всех методах чтения. Что если внешний класс, работающий в отдельном потоке, злонамеренно изменил состояниеskipLF
в середине чтения?BufferedReader
обязательно сойду с ума.Используй
public
поляВозьмите этот
Point
класс, например:Это сделает расчет расстояния между двумя точками очень болезненным для написания.
Класс не имеет никакого поведения, кроме простых методов получения и установки. Допустимо использовать открытые поля, когда класс представляет собой просто структуру данных, не имеет и никогда не будет иметь поведения (тонкие методы получения и установки не рассматриваются здесь). Это можно записать лучше так:
Чистота!
Но помните: не только в вашем классе должно отсутствовать поведение, но также не должно быть причин иметь поведение в будущем.
(Это именно то, что описывает этот ответ . Цитировать «Соглашения о коде для языка программирования Java: 10. Практика программирования») :
Таким образом, официальная документация также принимает эту практику.)
Кроме того, если вы уверены, что члены вышеупомянутого
Point
класса должны быть неизменяемыми, вы можете добавитьfinal
ключевое слово, чтобы обеспечить его выполнение:источник
Кстати, структура, которую вы даете в качестве примера, уже существует в библиотеке базовых классов Java как
java.awt.Point
. У него есть x и y в качестве открытых полей, проверьте сами .Если вы знаете, что делаете, и другие в вашей команде знают об этом, тогда можно использовать открытые поля. Но вы не должны полагаться на это, потому что они могут вызвать головную боль, как в ошибках, связанных с разработчиками, использующими объекты, как если бы они были структурами, размещенными в стеке (объекты Java всегда отправляются методам как ссылки, а не как копии).
источник
public final
поле, как в ответе Брайана, или с помощью публичного получателя, но без публичного установщика. То есть, неважно, использует ли человек поля или методы доступа.Re: аку, изб, Джон Топли ...
Остерегайтесь проблем изменчивости ...
Может показаться разумным не использовать геттеры / сеттеры. Это на самом деле может быть хорошо в некоторых случаях. Реальная проблема с предложенным шаблоном, показанным здесь, является изменчивостью.
Проблема в том, что вы передаете ссылку на объект, содержащую не окончательные открытые поля. Все остальное с этой ссылкой может свободно изменять эти поля. Вы больше не можете контролировать состояние этого объекта. (Подумайте, что произойдет, если строки будут изменяемыми.)
Плохо, когда этот объект является важной частью внутреннего состояния другого, вы только что раскрыли внутреннюю реализацию. Чтобы предотвратить это, вместо этого должна быть возвращена копия объекта. Это работает, но может вызвать огромное давление GC из-за тонны созданных одноразовых копий.
Если у вас есть открытые поля, рассмотрите возможность сделать класс доступным только для чтения. Добавьте поля в качестве параметров в конструктор и отметьте поля как окончательные. В противном случае убедитесь, что вы не выставляете внутреннее состояние, и если вам нужно создать новые экземпляры для возвращаемого значения, убедитесь, что оно не будет вызываться чрезмерно.
См .: « Эффективная Ява » Джошуа Блоха - Пункт № 13: Неизменность в пользу.
PS: Также имейте в виду, что все JVM в эти дни будут оптимизировать getMethod, если это возможно, в результате всего лишь одна инструкция чтения поля.
источник
Я пробовал это в нескольких проектах, основываясь на теории, согласно которой методы получения и установки загромождают код семантически бессмысленным перебором, и что другие языки, похоже, прекрасно справляются с традиционным сокрытием данных или разделением обязанностей (например, python).
Как уже отмечалось выше, есть 2 проблемы, с которыми вы сталкиваетесь, и они не могут быть исправлены:
И это в лучшем случае сценарий работы полностью в частном частном проекте. Как только вы экспортируете все это в общедоступную библиотеку, эти проблемы станут еще больше.
Ява очень многословна, и это заманчиво. Не делай этого.
источник
Если путь Java - это путь OO, то да, создание класса с открытыми полями нарушает принципы сокрытия информации, которые говорят, что объект должен управлять своим собственным внутренним состоянием. (Так как я не просто излагаю на вас жаргон, преимущество сокрытия информации заключается в том, что внутренняя работа класса скрыта за интерфейсом - скажем, вы хотели изменить механизм, с помощью которого ваш класс struct сохранил одно из своих полей, вам, вероятно, придется вернуться и изменить любые классы, которые используют класс ...)
Вы также не можете воспользоваться поддержкой классов, совместимых с именами JavaBean, что может повредить, если вы решите, скажем, использовать класс на странице JavaServer, написанной с использованием языка выражений.
Статья JavaWorld « Почему методы Getter и Setter являются злом» также может быть интересна для размышления о том, когда не следует реализовывать методы accessor и mutator.
Если вы пишете небольшое решение и хотите минимизировать объем используемого кода, способ Java может быть неправильным - я думаю, это всегда зависит от вас и проблемы, которую вы пытаетесь решить.
источник
В этом типе кода нет ничего плохого, если автор знает, что они являются структурами (или шаттлами данных), а не объектами. Многие Java-разработчики не могут отличить правильно сформированный объект (не просто подкласс java.lang.Object, но настоящий объект в определенной области) и ананас. Поэтому они в конечном итоге пишут структуры, когда им нужны объекты и наоборот.
источник
Проблема с использованием доступа к общедоступным полям та же, что и при использовании нового вместо заводского метода - если вы передумаете позже, все существующие вызывающие абоненты будут прерваны. Таким образом, с точки зрения развития API, обычно неплохо кусать пули и использовать методы получения / установки.
Одно место, куда я иду другим путем, - это когда вы строго контролируете доступ к классу, например, во внутреннем статическом классе, используемом в качестве внутренней структуры данных. В этом случае может быть гораздо понятнее использовать полевой доступ.
Кстати, по утверждению e-bartek, очень маловероятно, что IMO будет добавлена поддержка свойств в Java 7.
источник
Я часто использую этот шаблон при создании закрытых внутренних классов, чтобы упростить мой код, но я бы не рекомендовал выставлять такие объекты в публичном API. В общем, чем чаще вы можете сделать объекты в вашем публичном API неизменяемыми, тем лучше, и невозможно создать свой «структурный» объект неизменным образом.
Кроме того, даже если бы я писал этот объект как частный внутренний класс, я все равно предоставлял бы конструктор, чтобы упростить код для инициализации объекта. Необходимость иметь 3 строки кода, чтобы получить пригодный для использования объект, когда это будет сделано, просто беспорядок.
источник
Очень-очень старый вопрос, но позвольте мне сделать еще один небольшой вклад. Java 8 представила лямбда-выражения и ссылки на методы. Лямбда-выражения могут быть простыми ссылками на методы и не объявлять «истинное» тело. Но вы не можете «преобразовать» поле в ссылку на метод. таким образом
не законно, но
является.
источник
data -> data.x
, что все еще разумноЯ не вижу вреда, если вы знаете, что это всегда будет простая структура и что вы никогда не захотите привязывать к ней поведение.
источник
Это вопрос объектно-ориентированного проектирования, а не языка Java. Обычно рекомендуется скрывать типы данных внутри класса и предоставлять только те методы, которые являются частью API класса. Если вы выставите внутренние типы данных, вы никогда не сможете изменить их в будущем. Если вы их скрываете, ваше единственное обязательство перед пользователем - это метод return и типы аргументов.
источник
Здесь я создаю программу для ввода имени и возраста 5 разных людей и выполняю сортировку по возрасту. Я использовал класс, который действует как структура (например, язык программирования C), и основной класс для выполнения всей операции. Ниже я предоставляю код ...
Приведенный выше код не содержит ошибок и протестирован ... Просто скопируйте и вставьте его в свою IDE и ... Вы знаете и что ??? :)
источник
Вы можете создать простой класс с открытыми полями и без методов в Java, но он по-прежнему является классом и все еще обрабатывается синтаксически и с точки зрения распределения памяти, как класс. Нет способа по-настоящему воспроизвести структуры в Java.
источник
Иногда я использую такой класс, когда мне нужно вернуть несколько значений из метода. Конечно, такой объект недолговечный и с очень ограниченной видимостью, так что все должно быть в порядке.
источник
Как и в большинстве случаев, есть общее правило, а затем есть конкретные обстоятельства. Если вы делаете закрытое захваченное приложение, чтобы знать, как будет использоваться данный объект, вы можете воспользоваться большей свободой, чтобы улучшить видимость и / или эффективность. Если вы разрабатываете класс, который будет использоваться публично другими, не зависящими от вас, тогда склоняйтесь к модели получателя / установщика. Как и во всем, просто используйте здравый смысл. Часто нормально провести начальный раунд с публикой, а затем поменять их на геттер / сеттеры.
источник
Аспектно-ориентированное программирование позволяет вам перехватывать назначения или выборки и присоединять к ним перехватывающую логику, которая, как я предлагаю, является правильным способом решения проблемы. (Вопрос о том, должны ли они быть публичными, защищенными или защищенными пакетами, является ортогональным.)
Таким образом, вы начинаете с неперехваченных полей с правильным квалификатором доступа. Когда требования к вашей программе растут, вы присоединяете логику для проверки, делаете копию возвращаемого объекта и т. Д.
Философия получения / установки устанавливает затраты на большое количество простых случаев, когда они не нужны.
Является ли аспектный стиль чище или нет, это несколько качественно. Мне было бы легко видеть только переменные в классе и просматривать логику отдельно. Фактически, смыслом для Apect-ориентированного программирования является то, что многие проблемы являются сквозными, и разделение их на части в самом теле класса не является идеальным (регистрация в качестве примера - если вы хотите регистрировать все, получает от Java то, чего вы хотите) написать целую кучу геттеров и синхронизировать их, но AspectJ позволяет вам использовать одну строку).
Вопрос IDE - это красная сельдь. Это не столько печатание, сколько чтение и визуальное загрязнение, возникающее из-за get / sets.
На первый взгляд аннотации похожи на аспектно-ориентированное программирование, однако они требуют от вас исчерпывающего перечисления pointcut, добавляя аннотации, в отличие от краткой спецификации подстановки точек в AspectJ.
Я надеюсь, что осведомленность об AspectJ мешает людям преждевременно осваивать динамические языки.
источник