Структурировать подобные объекты в Java

Это полностью противоречит 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();
}

Вместо общедоступных изменяемых полей рассмотрите либо общедоступные неизменяемые поля, либо изменяемые поля локального пакета. Либо лучше ИМХО.

Peter Lawrey 25.04.2010 15:46

Помните, что, хотя геттеры и сеттеры уродливы / многословны, это своего рода сердце Java. Это лаконичный язык. С другой стороны, вы НИКОГДА не должны вводить что-либо из этого, поскольку это то, что ваша IDE делает за вас. На динамическом языке вам нужно меньше печатать, но вы должны печатать (как правило, хотя IDE могут помочь).

Dan Rosenstark 01.05.2010 20:47

По иронии судьбы, хотя OO имеет свои сильные стороны с точки зрения инкапсуляции, есть цена, которую нужно заплатить с точки зрения ЦП и хранилища. Сборщик мусора (почти полностью) устраняет необходимость беспокоиться о том, когда следует очистить ссылки на объекты. Текущая тенденция завершается полным кругом за счет использования C-подобных структур вне кучи. Это идеально подходит для решений типа кэширования, межпроцессного взаимодействия, более быстрых операций с интенсивным использованием памяти, более низкой производительности сборки мусора и даже выигрыша от более низкой производительности хранения для ваших наборов данных. Если вы знаете, что делаете, вы бы не задавали этот вопрос ... так что подумайте еще раз!

user924272 21.04.2014 03:19

@ user924272: Re "Текущая тенденция идет полным ходом за счет использования C-подобных структур вне кучи". Что бы вы сделали на Java как ??? ИМХО, это та область, где Java показывает свой возраст ...

ToolmakerSteve 18.06.2014 03:17

@ToolmakerSteve -Я вижу круг. Я не один. Такие компании, как Azul, стремятся к безостановочной сборке мусора. Ява старая. Истинный. Инженеры, которые обнаруживают слабость и что-то с ней делают, а не стонут? Они заслуживают уважения! +10 к Азулу от меня :-)

user924272 20.06.2014 06:04
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
196
5
349 952
20
Перейти к ответу Данный вопрос помечен как решенный

Ответы 20

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

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

Вы также не можете воспользоваться преимуществами поддержки классов, совместимых с именами JavaBean, что повредит, если вы решите, скажем, использовать класс на странице JavaServer, написанной с использованием языка выражений.

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

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

+1 за ссылку на статью "Почему методы Getter и Setter плохи". Однако ваш ответ был бы более ясным, если бы вы указали, что ОБЕ общедоступные поля И общедоступные геттеры / сеттеры НЕ ЯВЛЯЮТСЯ способом Java: как объясняется в этой статье - по возможности не делайте ни того, ни другого. Вместо этого предоставьте клиентам методы, специфичные для того, что им нужно делать, вместо того, чтобы отражать внутреннее представление экземпляра. ОДНАКО, это на самом деле не решает задаваемый вопрос (какой использовать для простого случая "структуры"), на который лучше ответить developer.g, izb и Брайан.

ToolmakerSteve 18.06.2014 02:56
Ответ принят как подходящий

Это часто обсуждаемая тема. Недостаток создания общедоступных полей в объектах заключается в том, что вы не можете управлять значениями, которые им задаются. В групповых проектах, где много программистов используют один и тот же код, важно избегать побочных эффектов. Кроме того, иногда лучше вернуть копию объекта поля или как-то его преобразовать и т. д. Вы можете смоделировать такие методы в своих тестах. Если вы создадите новый класс, вы можете увидеть не все возможные действия. Это похоже на защитное программирование - когда-нибудь геттеры и сеттеры могут оказаться полезными, и их создание / использование не требует больших затрат. Так что иногда они полезны.

На практике у большинства полей есть простые геттеры и сеттеры. Возможное решение могло бы выглядеть так:

public property String foo;   
a->Foo = b->Foo;

Обновление: маловероятно, что поддержка свойств будет добавлена ​​в Java 7 или, возможно, когда-либо. Другие языки JVM, такие как Groovy, Scala и т. д., Теперь поддерживают эту функцию. - Алекс Миллер

Это очень плохо, мне нравятся свойства в стиле C# (похоже на то, о чем вы говорите)

Jon Onstott 26.04.2011 02:26

Так что используйте перегрузку ... private int _x; public void x (int value) {_x = value; } public int x () {return _x; }

Gordon 08.01.2012 00:44

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

Svish 17.01.2012 16:40

@Gordon: Вы даже можете опустить _ в имени переменной, потому что x и x() - это две совершенно разные вещи в Java. Так что public void x(int value) { x = value; } подойдет.

T-Bull 14.08.2013 12:54

@ T-Bull: То, что у вас МОЖЕТ быть два x, это разные вещи, не делает это хорошей идеей. ИМХО, это плохое предложение, так как это может ввести в заблуждение читателей. Основной принцип: не заставляйте читателя переусердствовать; сделайте очевидным то, что вы говорите - используйте разные имена для разных сущностей. Даже если разница заключается только в добавлении подчеркивания. Не полагайтесь на окружающие знаки препинания, чтобы различать объекты.

ToolmakerSteve 18.06.2014 02:14

@ToolmakerSteve: «Это может привести к путанице» - это самый распространенный и до сих пор самый слабый аргумент, когда дело доходит до защиты догмы кодирования (в отличие от стиля кодирования). Всегда найдется кто-то, кого МОЖЕТ запутать самые простые вещи. Вы всегда найдете кого-то, кто будет жаловаться на то, что он сделал ошибку после того, как не спал и кодировал полнедели или около того, а затем обвинял вводящий в заблуждение стиль кодирования. Я не позволяю этому считаться. Этот стиль действителен, очевиден и сохраняет пространство имен в чистоте. Кроме того, здесь нет разных сущностей, есть / one / entity и какой-то шаблонный код вокруг него.

T-Bull 25.06.2014 12:47
Недостаток создания общедоступных полей в объектах заключается в том, что вы не можете управлять значениями, которые им задаются. this is not true at all, never has been public final String s; must be set in a constructor, where you have absolute control over it.
user177800 03.08.2018 06:54

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

Кстати, структура, которую вы даете в качестве примера, уже существует в библиотеке базовых классов Java как java.awt.Point. Он имеет x и y как общедоступные поля, Убедитесь сами.

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

+1 Хорошее упоминание о проблеме - способ, которым результат все еще НЕ похож на структуру C. Однако проблема, которую вы поднимаете о том, что объекты java всегда находятся по ссылке, не улучшается путем создания установщика вместо наличия общедоступного записываемого поля (что является сутью вопроса OP - какое представление использовать). Скорее, это аргумент в пользу НИЧЕГО. Это аргумент в пользу НЕПРЕРЫВНОСТИ. Это можно сделать либо как поле public final, как в ответе Брайана, либо с помощью общедоступного получателя, но без общедоступного установщика. То есть, использовать ли вы поля или методы доступа, не имеет значения.

ToolmakerSteve 18.06.2014 03:09

Правильно руководствуйтесь здравым смыслом. Если у вас есть что-то вроде:

public class ScreenCoord2D{
    public int x;
    public int y;
}

Тогда нет смысла оборачивать их геттерами и сеттерами. Вы никогда не собираетесь хранить координаты x, y в целых пикселях другим способом. Геттеры и сеттеры вас только замедлят.

С другой стороны, с:

public class BankAccount{
    public int balance;
}

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

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

Я согласен с этим ответом и говорю, что вы можете создать класс с общедоступными полями, если поля не зависят друг от друга смелый. т.е. одно поле не зависит от другого. Это может быть весьма полезно во многих случаях для множественных значений, возвращаемых функцией, или для полярных совпадений. {angle, length}, которые идут вместе, но никак не зависят друг от друга.

Spacen Jasset 06.06.2012 00:05

@SpacenJasset: К вашему сведению, я не понимаю, как ваши примеры (несколько возвращаемых значений; полярные координаты) имеют какое-либо отношение к тому, использовать ли общедоступные поля или геттеры / сеттеры. В случае нескольких возвращаемых значений это может даже быть контрпродуктивным, потому что, возможно, вызывающий должен ПОЛУЧАТЬ только возвращаемые значения, что свидетельствует в пользу общедоступных геттеров и частных сеттеров (неизменяемых). Это также может быть верно для возврата полярных координат из объекта (x, y) - рассмотрите НАКОПИТЕЛЬНЫЕ математические ошибки, поскольку изменения отдельных компонентов полярных координат преобразуются обратно в (x, y).

ToolmakerSteve 18.06.2014 02:29

@SpacenJasset: Но я согласен с вашим принципом.

ToolmakerSteve 18.06.2014 02:35

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

Horsey 29.03.2018 14:11

Re: аку, изб, Джон Топли ...

Остерегайтесь проблем с изменчивостью ...

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

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

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

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

См .: «Эффективная Java» Джошуа Блоха - Пункт № 13: Поддерживайте неизменность.

PS: Также имейте в виду, что все JVM в наши дни будут оптимизировать getMethod, если это возможно, в результате чего будет всего одна инструкция чтения поля.

Как геттер / сеттер решает эту проблему. У вас еще есть ссылка, у вас нет синхронизации с операциями. Геттеры / сеттеры сами по себе не обеспечивают защиту.

he_the_great 23.11.2008 21:39

При необходимости геттеры и сеттеры могут обеспечить синхронизацию. Вы также ожидаете, что геттеры и сеттеры будут делать гораздо больше, чем они были указаны. Независимо от этого проблема синхронизации все равно остаётся.

user924272 13.04.2014 03:13

Чтобы решить проблемы изменчивости, вы можете объявить x и y окончательными. Например:

class Data {
  public final int x;
  public final int y;
  public Data( int x, int y){
    this.x = x;
    this.y = y;
  }
}

Вызывающий код, который пытается выполнить запись в эти поля, получит ошибку времени компиляции «поле x объявлено окончательным; не может быть назначено».

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

public class DataTest {
    public DataTest() {
        Data data1 = new Data(1, 5);
        Data data2 = new Data(2, 4);
        System.out.println(f(data1));
        System.out.println(f(data2));
    }

    public int f(Data d) {
        return (3 * d.x) / d.y;
    }

    public static void main(String[] args) {
        DataTest dataTest = new DataTest();
    }
}

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

ToolmakerSteve 18.06.2014 02:44

@ToolmakerSteve - спасибо за отзыв - очень признателен.

Brian 19.06.2014 23:20

Я попытался использовать конечные экземпляры конечного класса с конечными полями в качестве «экземпляров» структуры, но в выражении case, относящемся к такому полю экземпляра, я получил Case expressions must be constant expressions. как это обойтись? что здесь за идиоматическое понятие?

n611x007 08.07.2014 19:28

Поля final по-прежнему являются ссылками на объекты, которые не являются константами, поскольку они будут инициализированы при первом использовании класса. Компилятор не может знать «значение» объектных ссылок. При компиляции необходимо знать константы.

Johan Tidén 10.10.2014 17:11
+1 Really important answer. The usefulness of immutable classes cannot be underestimated in my opinion. Their "fire-and-forget" semantics make reasoning about code often simpler, especially in multithreaded environments, where they can be shared arbitrarily between threads, without synchronization.
TheOperator 07.03.2016 18:23

Проблема с использованием доступа к общедоступным полям такая же, как и при использовании нового вместо фабричного метода - если вы передумаете позже, все существующие вызывающие объекты будут сломаны. Итак, с точки зрения эволюции API, обычно рекомендуется укусить пулю и использовать геттеры / сеттеры.

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

Между прочим, по утверждению e-bartek, весьма маловероятно, что, IMO, поддержка свойств будет добавлена ​​в Java 7.

Это правда, но если вы используете Java, это не проблема, так как вы можете реорганизовать всю базу кода одним щелчком мыши (Eclipse, Netbeans, возможно, VIM и Emacs). Если вы выбрали одного из его динамических друзей, например Groovy, даже простая инкапсуляция может потребовать от вас исправления в течение нескольких часов или дней. К счастью, у вас есть тестовые примеры, которые проинформируют вас ... сколько еще кода вам нужно исправить.

Dan Rosenstark 01.05.2010 20:28

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

Alex Miller 05.05.2010 05:27

Я часто использую этот шаблон при создании частных внутренних классов, чтобы упростить свой код, но я бы не рекомендовал раскрывать такие объекты в общедоступном API. В общем, чем чаще вы можете делать объекты в своем общедоступном API неизменяемыми, тем лучше, и невозможно создать свой «структурно-подобный» объект неизменяемым образом.

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

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

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

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

Как уже отмечалось выше, есть 2 проблемы, с которыми вы сталкиваетесь, и на самом деле они не решаемы:

  • Практически любой автоматизированный инструмент в мире Java полагается на соглашение о получении и установке. То же самое, как отмечали другие, теги jsp, конфигурация пружины, инструменты eclipse и т. д. И т. Д. Борьба с тем, что ожидают увидеть ваши инструменты, - это рецепт для долгих сеансов, проходящих через Google, пытаясь найти этот нестандартный способ запуска Spring beans. На самом деле не стоит беспокоиться.
  • Если у вас есть элегантно закодированное приложение с сотнями общедоступных переменных, вы, вероятно, найдете по крайней мере одну ситуацию, в которой их недостаточно - когда вам абсолютно необходима неизменяемость, или вам нужно вызвать какое-то событие, когда переменная будет установлена, или вы хотите выбросить исключение при изменении переменной, потому что оно устанавливает состояние объекта на что-то неприятное. Затем вы застряли перед незавидным выбором между загромождением вашего кода каким-либо специальным методом везде, где переменная напрямую упоминается, имея некоторую специальную форму доступа для 3 из 1000 переменных в вашем приложении.

И это в лучшем случае полностью работать в автономном частном проекте. Как только вы экспортируете все это в общедоступную библиотеку, эти проблемы станут еще больше.

Java очень многословен, и это очень соблазнительно. Не делай этого.

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

ToolmakerSteve 18.06.2014 03:02

В этом типе кода нет ничего плохого, при условии, что автор знает представляет собой структуры (или шаттлы данных), а не объекты. Многие разработчики Java не могут отличить хорошо сформированный объект (не только подкласс java.lang.Object, но и объект истинный в определенном домене) и ананас. Следовательно, они в конечном итоге пишут структуры, когда им нужны объекты, и наоборот.

ананас смешит меня :)

Guillaume 14.05.2012 19:32

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

ToolmakerSteve 18.06.2014 03:04

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

luis.espinal 26.06.2014 17:21

Более того, единственный неквалифицированный разработчик, который не должен знать разницы, - это тот, кто еще учится в школе. Это чрезвычайно важно, например, знание разницы между связанным списком и хеш-таблицей. Если человек получает 4-летнюю степень в области программного обеспечения, не зная, что такое настоящий объект, то либо этот человек не подходит для этой карьеры, либо он / она должны вернуться в школу и потребовать возмещения. Я серьезно.

luis.espinal 26.06.2014 17:23

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

luis.espinal 26.06.2014 17:25

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

Похоже, что многие люди, занимающиеся Java, не знакомы с Руководством по кодированию Sun Java. которые говорят, что вполне уместно использовать общедоступную переменную экземпляра, когда класс по сути, «структура», если Java поддерживает «структуру» (когда нет поведения).

Люди склонны думать, что геттеры и сеттеры - это способ Java, как будто они лежат в основе Java. Это не так. Если вы следуете Sun Java Рекомендации по кодированию с использованием переменных публичного экземпляра в соответствующих ситуациях, вы на самом деле пишете лучший код, чем загромождаете его ненужными геттерами и сеттерами.

Соглашения о коде Java с 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

+1 За действительно авторитетный источник. Любой другой ответ - это люди, выдвигающие свои мнения, как будто они являются фактами.

ArtOfWarfare 03.10.2012 16:20

Существует спецификация Java Beans, которая является отраслевым стандартом для доступа к свойствам с использованием методов get и set ... см. en.wikipedia.org/wiki/JavaBeans для обзора.

user924272 13.04.2014 03:10

@ user924272: Как эта спецификация Java Beans имеет отношение к этому ответу, в котором обсуждается, когда уместно использовать «общедоступные переменные экземпляра»? Если бы спецификация была стандартным способом автоматического превращения переменных экземпляра в свойства, например, C#, это могло бы быть актуально. Но это ведь не так? Он просто указывает наименование шаблонных методов получения и установки, которые необходимо создать для создания такого сопоставления.

ToolmakerSteve 18.06.2014 02:42

@ToolmakerSteve. Это вопрос java. Кроме того, вопрос ускользает от общей проблемы, когда существует спецификация. С точки зрения старой школы, гораздо проще отлаживать мутации полей, когда есть стандартный способ сделать это - установить точку останова в установщике. Это, вероятно, устарело с современными отладчиками, но я вынужден осуждать классы, которые напрямую «пробивают» объекты ... хотя это нормально для небольших приложений, это настоящая головная боль для больших приложений и крупных организаций.

user924272 20.06.2014 05:53

Это должен быть принятый ответ

StephenBoesch 06.02.2021 17:34

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

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

Философия геттера / сеттера требует затрат в большом количестве простых случаев, когда они не нужны.

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

Проблема IDE - отвлекающий маневр. Это не столько набор текста, сколько чтение и визуальное загрязнение, возникающее из-за get / sets.

Аннотации на первый взгляд кажутся похожими на аспектно-ориентированное программирование, однако они требуют, чтобы вы исчерпывающе перечислили pointcut, прикрепив аннотации, в отличие от краткой спецификации pointcut в стиле подстановочных знаков в AspectJ.

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

У AOJ есть обратная сторона - непрозрачная обработка и придание веса стадии прекомпиляции. Новичку в проекте может быть очень сложно понять, что делает код, а также как вносить изменения. Я говорю об этом, исходя из опыта проекта 5K SLOC, который казался на несколько X больше из-за сложности определения того, что на самом деле происходит.

StephenBoesch 06.02.2021 17:37

Здесь я создаю программу для ввода имени и возраста 5 разных людей и выполняю сортировку (по возрасту). Я использовал класс, который действует как структура (например, язык программирования C), и основной класс для выполнения всей операции. Ниже я представляю код ...

import java.io.*;

class NameList {
    String name;
    int age;
}

class StructNameAge {
    public static void main(String [] args) throws IOException {

        NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object
        NameList temp=new NameList(); // Create a temporary object of the structure

        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

        /* Enter data into each radix of 'nl' object */

        for(int i=0; i<5; i++) {
            nl[i]=new NameList(); // Assign the structure into each radix

            System.out.print("Name: ");
            nl[i].name=br.readLine();

            System.out.print("Age: ");
            nl[i].age=Integer.parseInt(br.readLine());

            System.out.println();
        }

        /* Perform the sort (Selection Sort Method) */

        for(int i=0; i<4; i++) {
            for(int j=i+1; j<5; j++) {
                if (nl[i].age>nl[j].age) {
                    temp=nl[i];
                    nl[i]=nl[j];
                    nl[j]=temp;
                }
            }
        }

        /* Print each radix stored in 'nl' object */

        for(int i=0; i<5; i++)
            System.out.println(nl[i].name+" ("+nl[i].age+")");
    }
}

Приведенный выше код не содержит ошибок и протестирован ... Просто скопируйте и вставьте его в свою среду IDE и ... Знаете и что ??? :)

Очень-очень старый вопрос, но позвольте мне сделать еще один небольшой вклад. В Java 8 появились лямбда-выражения и ссылки на методы. Лямбда-выражения могут быть простыми ссылками на методы и не объявлять «истинное» тело. Но вы не можете «преобразовать» поле в ссылку на метод. Таким образом

stream.mapToInt(SomeData1::x)

не законно, но

stream.mapToInt(SomeData2::getX)

является.

В этом случае вы можете использовать data -> data.x, что все еще разумно.

James Kraus 09.10.2018 00:22

Не используйте поля public

Не используйте поля public, если вы действительно хотите обернуть внутреннее поведение класса. Возьмем, к примеру, java.io.BufferedReader. В нем есть следующее поле:

private boolean skipLF = false; // If the next character is a line feed, skip it

skipLF читается и записывается всеми методами чтения. Что, если внешний класс, работающий в отдельном потоке, злонамеренно изменил состояние skipLF в середине чтения? BufferedReader определенно выйдет из строя.

Используйте поля public

Возьмем, к примеру, этот класс Point:

class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return this.x;
    }

    public double getY() {
        return this.y;
    }

    public void setX(double x) {
        this.x = x;
    }

    public void setY(double y) {
        this.y = y;
    }
}

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

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));

Класс не имеет другого поведения, кроме простых методов получения и установки. Допустимо использовать общедоступные поля, когда класс представляет только структуру данных и не имеет, и никогда не будет иметь поведения (тонкие геттеры и сеттеры - это нет, рассматриваемое здесь поведением). Лучше записать это можно так:

class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));

Чистый!

Но помните: не только ваш класс должен отсутствовать в поведении, но он также должен иметь причину нет для поведения в будущем.


(Это именно то, что описывает этот ответ. Процитируем «Соглашения о коде для языка программирования Java: 10. Практики программирования»:

One example of appropriate public instance variables is the case where the class is essentially a data structure, with no behavior. In other words, if you would have used a struct instead of a class (if Java supported struct), then it's appropriate to make the class's instance variables public.

Таким образом, официальная документация также принимает эту практику.)


Кроме того, если вы абсолютно уверены, что члены вышеуказанного класса Point должны быть неизменными, вы можете добавить ключевое слово final, чтобы обеспечить его соблюдение:

public final double x;
public final double y;

Другие вопросы по теме