Неизменный тип: общедоступные финальные поля против получателя - PullRequest
53 голосов
/ 03 августа 2011

Мне нужен маленький контейнерный класс для хранения некоторых строк, которые должны быть неизменяемыми. Поскольку сам String является неизменяемым типом, я подумал о чем-то таком:

public final class Immu
{
  public final String foo;
  public final String bar;

  public Immu(final String foo, final String bar)
  {
    this.foo = foo;
    this.bar = bar;
  }
}

Многие люди, похоже, вообще возражают против использования открытых полей и вместо этого используют Getters. ИМХО, в данном случае это будет просто шаблон, потому что сама String неизменна.

Другие мысли, которые я могу пропустить на этом?

Ответы [ 6 ]

52 голосов
/ 03 августа 2011

Я бы сделал то, что вы считаете самым простым и ясным. Если у вас есть класс значений данных, который используется только ограниченным числом классов. особенно пакет локальный класс. тогда я бы избегал getter / setters и использовал бы локальные или открытые поля пакета.

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

24 голосов
/ 03 августа 2011

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

14 голосов
/ 03 августа 2011

Этот ответ отменен:

Почему бы не

interface Immu { String getA() ; String getB ( ) }

Immu immu ( final String a , final String b )
{
       /* validation of a and b */
       return new Immu ( )
       {
              public String getA ( ) { return a ; }

              public String getB ( ) { return b ; }
       }
}
6 голосов
/ 19 апреля 2014

Я использую шаблон public-final-field (anti?) Для домашних проектов для классов, которые в основном представляют собой неизменную структуру данных с конструктором, наряду с абсолютными основами, такими как equals (), hashCode (), toString () и т. Д. . если необходимо. (Я избегаю слова «структура» из-за различных его толкований).

Я бы не стал применять этот подход к чужой кодовой базе (работа, общедоступный проект и т. Д.), Потому что он, скорее всего, будет несовместим с другим кодом, и принципы, такие как When In Rome или Least Surprise, имеют приоритет.

Тем не менее, что касается ответов Даниэля С. Собрала и aioobe, я отношусь к тому, что если дизайн класса становится проблемой из-за непредвиденных событий, в IDE будет работать 30 секунд, чтобы приватизировать поля и добавить средства доступа, и не более 5 или 10 минут, чтобы исправить испорченные ссылки, если их нет сотен. Все, что в результате проваливается, в первую очередь проходит модульное тестирование. :-)

[Редактировать: Эффективная Java довольно решительно против этой идеи, при этом отмечая, что она «менее вредна» для неизменных полей.]

5 голосов
/ 29 мая 2015

Я нашел эту ветку в надежде на какие-то реальные аргументы, но ответы, которые я видел здесь, не сильно мне помогли. После некоторых исследований и размышлений я думаю, что следует рассмотреть следующее:

  • public final выглядит наиболее чистым для неизменяемых типов.
  • Изменяемые типы могут быть изменены средствами доступа, даже если это не предусмотрено - в параллельных средах это может привести к большим головным болям.
  • Не может быть конструктора без аргументов. Это важно, если вам нужны фабричные методы (например, для LMAX Disruptor). Аналогичным образом создание экземпляров ваших объектов с помощью отражения становится более сложным.
  • Геттеры и сеттеры могут иметь побочные эффекты. Использование public final ясно говорит программисту, что никакой скрытой магии не происходит, и объект по своей сути тупой:)
  • Вы не можете вернуть оболочку или экземпляр производного класса для средства доступа. Опять же, это то, о чем вы должны знать, когда полю присваивается его значение. По моему мнению, контейнерные классы не должны беспокоиться о том, что кому возвращать.

Если вы находитесь в середине разработки, и никакие рекомендации не мешают вам, и проект изолирован, или у вас есть контроль над всеми вовлеченными проектами, я бы предложил использовать public final для неизменяемых типов. Если позже вы решите, что вам нужны геттеры, Eclipse предложит Refactor -> Encapsulate Field..., который автоматически создаст их и настроит все ссылки на поле.

0 голосов
/ 03 августа 2011

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

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