Являются ли Java Beans классами хранения данных плохим дизайном? - PullRequest
11 голосов
/ 25 июня 2010

Обычно JavaPractices.com - это хороший сайт с хорошими идеями, но меня это беспокоит: JavaBeans - это плохо .

В статье приводятся несколько причин, в основном это означает, что термин JavaBean означает «Java Bean - это программный компонент многократного использования, которым можно визуально манипулировать в инструменте разработчика». не Хранение данных, нарушает определенные шаблоны, и является более сложным.

Теперь я могу согласиться с последним, но в моих глазах JavaBeans в списке имеет гораздо больше смысла, чем вложенные Карты. В статье утверждается, что структуры отображения базы данных должны вызывать конструкторы, а не методы set *, и объект должен быть неизменным. Однако, на мой взгляд, вызов метода set * при попытке построить объект легче читать, чем new MappedObject("column1", "column2", "yet another column", "this is stupid");

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

Итак, мой вопрос: является ли использование JavaBeans для хранения данных плохой практикой и его следует избегать, или это совершенно безопасно?

Ответы [ 6 ]

20 голосов
/ 25 июня 2010

Кажется, вы неправильно читаете текст.

Теперь я могу согласиться с последним, но на мой взгляд JavaBeans в списке имеет гораздо больше смысла, чем вложенные Карты

Текст никогда не упоминает вложенные карты как альтернативу (yiack)

... должен вызывать конструкторы, а не набор * методов, и объект должен быть неизменным

Это хорошая практика, особенно полезная при работе с потоками.

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

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

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

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

Нет, это не плохая практика. Не совершенно безопасно тоже. Зависит от ситуации.

Проблема с изменяемыми объектами (а не с JavaBeans как таковыми) заключается в использовании различных потоков для доступа к ним.

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

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

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

class MyBean  {
    private final int i;
}

Если вы хотите присвоить разумное значение MyBean.i, вы должны указать его в конструкторе:

 public MyBean( int i ) {
     this.i = i;
 }

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

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

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

Если в будущем вам придется иметь дело с многопоточными приложениями, вы можете рассмотреть возможность использования неизменного JavaBean;)

Кстати, альтернатива для создания неизменяемых bean-компонентов и все еще предоставления набора сеттеров использует Builders, например:

 Employee e = new EmployeeBuilder()
                  .setName("Oscar")
                  .setLastName("Reyes")
                  .setAge(0x1F)
                  .setEmployeeId("123forme")
                  .build(); 

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

Если вам нужно изменить одно значение, вы можете использовать метод класса:

 Employee e = Employee.withName( e, "Mr. Oscar");

, который берет существующий объект, копирует все значения и устанавливает новый ....

 public static EmployeeWithName( Employee e , String newName ){
      return new Employee( newName, e.lastName, e.age, e.employeeId );
  }

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

PS Я настоятельно рекомендую вам купить эту книгу: Эффективная Java . Вы никогда не пожалеете об этом, и у вас будет информация, чтобы судить о лучших статьях, подобных цитируемой.

6 голосов
/ 26 июня 2010

Мое возражение против использования JavaBeans в качестве классов хранения данных заключается в том, что они допускают объекты с несовместимым состоянием.В типичном случае использования для таких bean-компонентов у вас есть следующие шаги:

  • создать экземпляр класса;
  • установить первое свойство;
  • установить второе свойство;
  • ...
  • установить конечное свойство;
  • использовать экземпляр объекта.

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

  • (Необязательно: настроить объект параметров) ;
  • создать экземпляр класса;
  • использоватьэкземпляр объекта.

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

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

4 голосов
/ 25 июня 2010

"У шаблона JavaBeans есть серьезные недостатки." & mdash; Джошуа Блох, Эффективная Ява

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

Кстати, в упомянутой книге (Effective Java) подробно обсуждаются обе эти модели, их преимущества, недостатки и альтернативы. Вы можете проверить это. Но нет ничего плохого в JavaBeans, просто иногда они не лучший выбор.

Редактировать: См. Пункт 2 («Рассмотреть конструктор, когда сталкиваешься со многими параметрами конструктора») в Эффективной Java на Google Книгах: http://books.google.com/books?id=ka2VUBqHiWkC&lpg=PP1&pg=PA11#v=onepage&q&f=false

2 голосов
/ 26 июня 2010

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

Если в итоге вы получите конструктор, который читает

new Person («param 1», «param 2», «param 3», «param 4», «param 5», «param 6», «param 7», «param 8»)

тогда ваш объект слишком сложен. Вам понадобятся объекты Parameter (см. Книгу «Рефакторинг Мартина Фаулера»).

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

Когда вам нужно изменить объект, добавьте конструктор копирования (то есть метод клона). Современные JVM справляются с этим легко и быстро, и скорость снижается. Вы также облегчаете работу Hotspot и GC.

0 голосов
/ 25 июня 2010

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

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

Тесты Whem начинают проваливаться из-за "плохих" Java-бинов, тогда я пересмотрю это повод для беспокойства. Но я не видел этого до сих пор. Единственный раз, когда я бы сказал, что они, вероятно, неуместны, - это использование общих бинов в многопоточном коде, поскольку синхронизировать общее изменяемое состояние довольно сложно. Держитесь подальше от этого, и бобы просто в порядке.

0 голосов
/ 25 июня 2010

Это совершенно безопасно и гораздо предпочтительнее, чем бесконечно вложенное java.util.Map. Вы получаете безопасность типов, облегчаете понимание кода и избегаете попадания своего кода в The Daily WTF. Обратите внимание, что реализация должна быть отделена - не смешивайте слишком много логики (помимо простой проверки) в ваших классах хранения данных. Вы должны прочитать о POJOs

...