 | Уровень сложности: средний Джефф Хэмбрик, инженер, IBM
06.05.2008 EJB Advocate анализирует сервис-ориентированную архитектуру сверху вниз, выясняя, какой EJB-компонент, сессионный или компонент управления данными, должен собирать объекты передачи данных, возвращаемые сервисом.
Из IBM WebSphere Developer Technical Journal.
В каждой статье EJB Advocate приводится типичный диалог с реальными пользователями и разработчиками в процессе предоставления рекомендаций по решению какой-либо интересной проблемы. Персональные данные участников диалога не сообщаются, также не используются недостаточно испытанные и закрытые архитектуры. Более подробная информация приведена в статье "Знакомство с EJB Advocate".
Роль EJB-компонентов управления данными в сервисах
В предыдущей статье рубрики мы представили некоторые характеристики сервис-ориентированных архитектур; например, чтобы минимизировать "разговоры" между сервисом и его клиентом, сервис должен быть крупномодульным, не сохраняющим состояния, а также желательно должен компоновать объект передачи данных (Data Transfer Object - DTO), который собирает все свойства, возвращаемые клиентскому приложению. Мы видели, как корректно спроектированные EJB-методы экспонируют эти характеристики, ассоциированные либо с экземпляром сессионного EJB-компонента, либо с home EJB-компонента управления данными. Однако в этом месяце читатель спрашивает, не далеко ли мы зашли, предлагая проектировать EJB-компоненты управления данными тоже в виде не сохраняющих состояния сервисов.
Проблема: какой объект передачи данных каким логическим объектом (entity) возвращается?
Уважаемый EJB Advocate!
Я недавно стал следить за Вашими статьями и должен прокомментировать статью об использовании объектов передачи данных (DTO). Я согласен с Вами в том, что они очень важны на уровне сервисов, где желательны крупномодульные методы, особенно для фасадов, представляющих сервисы и скрывающих реализацию, и особенно для удаленных фасадов (поскольку удаленная активизация намного дороже по ресурсам, чем локальная).
Далее, рекомендация реализовывать код, позволяющий запрашивать EJB-компонент управления данными "дай мне DTO самого себя" кажется разумной и хорошо инкапсулированной. Однако проблема заключается в том, что для двух различных вариантов использования в одном случае нужны некоторые атрибуты данного EJB-компонента управления данными, тогда как в другом случае могут понадобиться другие атрибуты - то есть нужны два DTO-класса. Какой тип DTO должен возвращать метод getDTO()?
Есть еще одна проблема. В различных вариантах использования может понадобиться DTO, составленный из нескольких экземпляров одного или разных типов (клиент, открытый заказ, товары в заказе). В каком EJB-компоненте управления данными Вы собираетесь реализовать такую составную функцию?
Похоже, трудно отказаться от использования индивидуальных методов getter (и setter) в EJB-компонентах управления данными в фасаде сессии. Преимуществом помещения логики компоновки DTO в сессионный компонент (или, как я предпочитаю, во вспомогательный класс, используемый сессией) является то, что не нужно беспокоиться о рассинхронизации пользовательского кода, если по каким-либо причинам необходимо удалить или сгенерировать логический объект повторно (например, добавление нового свойства для еще одного сервиса).
Я понимаю, что на самом деле мой вопрос можно сократить: не является ли ложной тревогой возврат DTO из CMP-компонентов управления данными, если Вы все равно рекомендуете использовать локальные интерфейсы к EJB-компонентам управления данными? Я понимаю Ваше желание минимизировать "разговоры" между уровнями, но, похоже, Вы жертвуете удобством эксплуатации ради производительности.
Never Cry Wolf (Не поднимай ложную тревогу)
Возьмите на заметку хорошую методику инкапсуляции
Уважаемый Never!
Вы сделали несколько хороших и достойных внимания замечаний. Давайте разберем вопросы по очереди, начиная с первого:
- Если два варианта использования нуждаются в различных данных, DTO какого типа должен возвращать метод getDTO()?
Дурацкий ответ – естественно, getDTO() должен возвращать экземпляр DTO. Если серьезно, имя, которое Вы выбираете для DTO, должно яcно указывать, какие данные возвращаются. Если два варианта использования требуют двух различных наборов данных, имя класса DTO должно указывать это: что-либо вроде UseCase1DTO или UseCase2DTO. Таким образом, методы в интерфейсе будут иметь две сигнатуры:
Фрагмент кода 1. Несколько сигнатур для DTO-методов
public UseCase1DTO getUseCase1DTO();
public UseCase2DTO getUseCase2DTO(); |
Или более абстрактно:
Фрагмент кода 2. Более понятный способ показать абстрактные примеры
И последнее серьезное замечание по соглашению: если Вы хотите иметь метод getDTO(), ассоциированный с логическим объектом, один из подходов - резервировать имя этого метода для того, который возвращает экземпляр <Entity>DTO, и этот DTO содержит все не скалярные свойства ассоциированного логического объекта (свойства с максимальным кардинальным числом 1). Ваша команда может выбрать другое соглашение, просто следуйте ему.
- Если задача требует данных из нескольких логических объектов (например, клиент, открытый заказ и товары в заказе), какой логический объект "владеет" методом get<ComposedDTO>()?
Ответ с точки зрения определения составного DTO-метода в EJB-компоненте управления данными содержится в лучших методиках объектно-ориентированного проектирования. Мы кратко затронули ОО-делегирование в статье "Создание высокопроизводительных EJB-компонентов управления данными, часть 2". Выбор логического объекта зависит от взаимосвязей между логическими объектами и данными, которые Вы хотите возвращать. Вообще говоря, желательно возвращать логический объект, который может делегировать другим логическим объектам составление целостной структуры. В Вашем конкретном примере Вы хотите, чтобы DTO возвращал данные из Customer, его открытого Order и Products в Order (представленные элементом Line Item для хранения атрибутов link для количества и суммы). Предположим на минутку, что диаграмма классов на рисунке 1 описывает бизнес-объекты и взаимоотношения между ними.
Рисунок 1. Пример диаграммы классов, показывающий логические объекты и взаимоотношения
Для Вашего примера естественным логическим объектом для "владения" составным DTO-методом будет Customer, поскольку он может делегировать объекту Order, который может делегировать объекту Line Item, который может делегировать объекту Product. В качестве названия метода для логического объекта Customer мы можем выбрать что-либо вроде getCustomerOpenOrderDetails().
Показанные на диаграмме взаимоотношения допускают несколько путей, по которым мы можем извлекать DTO, компонующий информацию из всех четырех типов логических объектов. Например:
- Для данного клиента извлечь подробности открытого заказа (как описано выше).
- Для данного клиента извлечь все подробности ассоциированного заказа.
- Для данного заказа извлечь имя клиента и подробности.
- Для данного элемента строки извлечь ассоциированный с ним товар, содержащий заказ и клиента.
- Для данного продукта извлечь все ассоциированные элементы строки заказа и клиентов.
Логический объект, владеющий методом, указан "для данного <Entity>" в выражении, приведенном выше, - он представляет начальную точку, то есть предполагается, что фасад любого сервиса (или метод home EJB-компонента), ассоциированный с этим методом, будет принимать параметры, которые могут идентифицировать один или несколько типов этого логического объекта для начала делегирования. Надеюсь, что ответил на Ваш второй вопрос.
- Не является ли ложной тревогой рекомендация возвращать DTO из EJB-компонентов управления данными и в то же время использовать локальные интерфейсы (принося простоту обслуживания в жертву производительности)?
Мы проводили подобный очень интересный анализ компромиссов еще во времена EJB 1.x и обнаружили, что относительно возврата данных из логических объектов было два крайних и один компромиссный подход, которые приводили к трем основным стилям доступа:
-
a. Один атрибут за раз
На первый взгляд наиболее простой для обслуживания подход - избегать всех DTO и получать от клиента один атрибут за раз. Но Вы жертвуете количеством и размером сообщений ради простоты эксплуатации. В среднем все заканчивается большим количеством маленьких сообщений и в конечном итоге накладными расходами при обмене данными, когда используемые удаленные интерфейсы оказывают основное влияние на время реакции и пропускную способность. Еще один минус (как Вы отметили) - нарушение инкапсуляции. Нарушение инкапсуляции негативно влияет на удобство эксплуатации. Например, если Вы решите факторизовать набор атрибутов в соответствующий логический объект, необходимо будет изменить каждое клиентское приложение, использующее эти атрибуты!
-
Один DTO на все случаи жизни
Другой крайностью является возврат всех нескалярных данных, ассоциированных с целевым логическим объектом, возвращаемым в DTO, как мы описывали выше в ответе на вопрос 1. В данном случае минимизируется количество сообщений удаленным интерфейсам и сохраняется удобство эксплуатации. Вы делаете только один вызов на логический объект и получаете все существующие данные. На один логический объект нужно разработать всего лишь один DTO и метод извлечения. Естественно, компромиссом является то, что DTO почти всегда содержит больше данных, чем необходимо для данной единицы работы, особенно для реальных логических объектов, имеющих большое количество атрибутов. Поэтому данный подход существенно влияет на объем извлекаемых и передаваемых данных для каждой единицы работы. Положительная сторона - каждый раз при добавлении или удалении атрибутов нужно изменять только DTO. Клиентское приложение нужно менять только тогда, когда оно использует удаляемый атрибут.
-
Специализированный DTO
Компромиссным подходом (напоминает сказку "Златовласка и три медведя") является приспосабливание структуры DTO для возврата только необходимого. Один вызов. Отличный размер. Все хорошо. Проблема заключается в том, что необходимо очень тщательно проанализировать вариант использования для формирования правильного набора DTO и методов. При реализации нового класса варианта использования нужно создавать новый DTO и настроить EJB для его извлечения.
При использовании логических объектов EJB 1.x вариант "c" считался наилучшим, поскольку разработка приложений с распределенными объектами требует минимизации количества вызовов (которые могут быть удаленными). Вариант "b" был удачным компромиссом для получения определенного удобства эксплуатации. Тогда времена были проще - не было этих ужасных CMR, заставляющих думать о "зависимых объектах" (кластерах свойств, которые на самом деле представляют объект, "содержащийся" в логическом объекте).
Но теперь, когда есть EJB 2.x с локальными интерфейсами и CMR, я не знаю, какой вариант является наилучшим (мы слегка коснулись этого вопроса в статье "Создание производительных EJB-компонентов управления данными, часть 1"). Однако мы не сдаем позиции и полагаем, что использование специализированных DTO, описанное в варианте "c", по-прежнему остается наилучшим по причине (хотя и не такой уж критичной) производительности. Мы также считаем, что поскольку многие уже использовали "оптимальные методики" EJB 1.x, этот вариант лучше, так как не нужно переучиваться (и он значительно облегчает переход на EJB 2.x).
Надеюсь, мой ответ будет вам полезен.
Ваш EJB Advocate
Еще раз о проблеме простоты эксплуатации
Уважаемый EJB Advocate!
Я понимаю ваши ответы на первые два вопроса и соглашаюсь с ними. Они очень помогли мне. Что касается Вашего анализа моего третьего вопроса, я понимаю, почему Вы считали вариант "c" лучшим во времена EJB 1.x с точки зрения производительности, но Вы на самом деле ничего не сказали о серьезной проблеме простоты эксплуатации, с которой можно столкнуться при использовании EJB 2.x.
Рассмотрим простую диаграмму из Вашего ответа. В ней пять различных "высокоуровневых" методов для компоновки информации из всех четырех логических объектов. Вы не упомянули методы, ассоциированные с каждым из них для управления делегированием. Просто взгляните на методы, ассоциированные с получением открытого заказа от пользователя:
- Для данного заказа возвратить его и элементы строки. Выполнить делегирование:
- Для данного элемента строки возвратить ее и товар. Выполнить делегирование:
- Для данного товара возвратить его DTO.
Далее, существуют композиции, которые не содержат все четыре логических объекта. Рассматривая только клиента, я могу представить еще три метода:
- Просто возвратить данные о клиенте и ничего более.
- Возвратить только данные о клиенте и открытом заказе (без подробностей).
- Возвратить данные о клиенте и всех ассоциированных заказах (опять же без подробностей).
Теперь добавьте к этому все комбинации для получения частичных атрибутов от каждого логического объекта. При окончательном анализе число комбинаций становится огромным, особенно если принять во внимание (как Вы сами сказали), что для каждого реального логического объекта существует значительно большее количество атрибутов.
Разве мой третий вопросе о том, что огромную часть простоты эксплуатации Вы приносите в жертву небольшому приросту производительности, не логичен?
Заранее спасибо, но я все еще должен подписаться как
Never Cry Wolf (Не поднимайте ложную тревогу)
Объекты передачи данных ассоциируются с представлениями
Уважаемый Never Cry Wolf
Я мог бы пошутить, что сейчас именно Вы поднимаете ложную тревогу. Вряд ли в реальном специализированном приложении будет слишком много комбинаций. Чтобы понять, что я имею в виду, давайте начнем сначала с вариантов использования. Хотя данная статья не претендует быть полным учебником по нашему подходу к объектно-ориентированному анализу и проектированию, мы кратко пройдемся по некоторым из основных артефактов, чтобы понять - число комбинаций будет относительно ограничено.
Показанные на диаграмме классов (рисунок 1) логические объекты ассоциируются с бизнес-процессом управления заказом. Этот процесс можно описать с помощью диаграммы состояний (State Transition Diagram - STD), например, такой, как на рисунке 2. На этой диаграмме показаны этапы жизненного цикла конкретного заказа.
Рисунок 2. Пример диаграммы состояний, демонстрирующей жизненный цикл заказа
Просто для информации рисунок 2 дополнен нотацией UML actor, отображающей владельца экземпляра на данном этапе. Мы используем это простое расширение уже много лет как способ организации вариантов использования и связывания их с бизнес-процессом (на самом деле мы любим шутить, что диаграмма вариантов использования - это просто диаграмма состояний, которая еще не закончена).
Еще один подход, который мы используем несколько нестандартно, - это разработка диаграммы классов для каждого состояния в модели жизненного цикла, чтобы показать ограничения для атрибутов и взаимоотношения в данном состоянии. Эти изменяющиеся ограничения теряются в "монолитной" диаграмме классов, которая не учитывает состояния. Например, диаграмма классов на рисунке 1 показывает взаимоотношения и атрибуты, соответствующие состоянию open жизненного цикла, показанного на рисунке 2. Диаграмма классов для заказа в состоянии submitted может выглядеть примерно так, как показано на рисунке 3.
Рисунок 3. Пример диаграммы классов, показывающий заказ в состоянии submitted
Такой подход к предоставлению отдельных диаграмм классов для состояния объясняет, почему некоторые классы на рисунке 3 и 1 используют [] в имени класса для индикации состояния, связывая "динамическую" модель переходов состояний со "статической" диаграммой классов. Сравнивая рисунок 1 и рисунок 3, легко можно увидеть изменение в "форме" Order по мере прохождения заказа из состояния open в состояние submitted в бизнес-процессе, показанном на рисунке 2. Состояния на рисунке 2 показывают изменения в поведении.
Совместно статическая и динамическая модели определяют полный набор сервисов в сервис-ориентированной архитектуре. Каждое состояние в модели жизненного цикла может быть отображено один-в-один на сессионный EJB-компонент. Каждый переход в STD-карте отображается в метод сессионного компонента, ассоциированного с состоянием, и управляет обновлениями. Каждый класс в модели взаимоотношений может быть отображен на EJB-компонент управления данными. Взаимоотношения в диаграмме естественным образом отображаются на CMR. То есть можно сделать вывод, что для двух состояний, opened и submitted, будет иметься два сессионных EJB-компонента с четырьмя и тремя методами update в каждом. Для двух приведенных диаграмм классов можно сделать вывод, что всего будет 15 EJB-компонентов управления данными с некоторым количеством атрибутов и CMR.
Конкретнее, давайте возьмем состояние заказа open в качестве примера. Мы любим начинать с чистого Java-интерфейса, который везде можем использовать повторно:
Фрагмент кода 3. Чистый Java-интерфейс, показывающий методы, полученные из STD
public interface OpenOrder {
OrderKey open(CustomerKey cust)
throws CustomerNotFound, OrderAlreadyOpen;
int addLineItem(CustomerKey cust, ProductKey product, int qty)
throws CustomerNotFound, OrderNotOpen, InvalidQuantity;
void submit(CustomerKey cust)
throws CustomerNotFound, OrderNotOpen, OrderHasNoLineItems;
void cancel(CustomerKey cust)
throws CustomerNotFound, OrderNotOpen;
} |
Этот интерфейс можно повторно использовать в интерфейсе сессионного EJB-компонента, реализовав его примерно так:
Фрагмент кода 4. Интерфейс сессионного компонента и класс реализации
public interface OpenOrderSession
extends javax.ejb.EJBLocalObject, OpenOrder;
public class OpenOrderSessionBean
implements javax.ejb.SessionBean
{
// здесь находятся реализации
} |
При желании можно использовать методы EJB Home вместо сессионных EJB-компонентов. В этом случае логический объект Customer становится естественным "шлюзом" к бизнес-логике, поскольку он представляет собой actor, управляющего бизнес-процессом в данном состоянии. В данной ситуации можно просто расширить тот же интерфейс OpenOrder, который создан для сессии, как показано в следующем фрагменте кода:
Фрагмент кода 5. Интерфейс home логического объекта Customer, повторно использующий интерфейс OpenOrder
public interface CustomerHome
extends javax.ejb.EJBLocalHome, OpenOrder
{
// другие Home-методы, например, findByPrimaryKey() и create()
}
|
Какой бы подход ни был избран, эти методы и отображения дают Вам компоненты, необходимые для реализации методов update. Эти динамические и статические модели можно было бы использовать также для получения всех методов read, если бы мы прошли через все комбинации, перечисленные в Вашем анализе. Но мы решили, что будет лучше получить методы read из последовательности экранов (screen flow) пользовательского интерфейса (User Interface - UI), который предоставляет данные, необходимые для поддержки активизации функций бизнес-процесса.
Для документирования последовательности экранов нам тоже нравится использовать диаграммы состояний. STD-последовательности экранов можно рассматривать как снимок жизненного цикла типичной "сессии" субъекта actor, который владеет состоянием в модели бизнес-процесса. Состояния показывают экраны и всплывающие диалоговые окна, тогда как переходы показывают события, инициированные пользователем. Для иллюстрации этого на рисунке 4 изображена последовательность экранов для пользователя, показывающая, как он взаимодействует с процессом управления заказами.
Рисунок 4. Пример последовательности экранов для сессии управления заказами пользователя
Взаимодействия между моделями, если они есть, указываются внутри {} на переходах, показывая побочные эффекты в терминах активизации переходов в бизнес-процессе. Некоторые события (например, submit) входят в состояние диалога подтверждения. Только активизация пользователем события "ОК" приводит к побочному эффекту - реальному подтверждению факта заказа. Эти состояния подтверждения показаны курсивом.
Еще одно состояние, показанное курсивом, – это состояние "Home", представляющее, как данная роль (Customer в этом случае) инициирует и завершает свою сессию. И еще одно специальное состояние, показанное курсивом, ассоциируется с бизнес-процессом, поскольку данный субъект actor может взаимодействовать с несколькими процессами. Оба этих состояния являются специальными, потому что они – всего лишь навигация (обычно они отображаются в виде меню или закладок в зависимости от стиля пользовательского интерфейса).
Остальные состояния представляют "реальные" экраны (или фрагменты экранов; мы оставим эту дискуссию для следующих статей, поскольку она затрагивает общие оптимальные методики использования J2EE). Для каждого экрана (специальный он или нет) можно использовать диаграмму классов для захвата видимых данных для этого состояния, аналогично тому, как диаграмма классов, ассоциированная с бизнес-процессом, показывает персистентные данные, ассоциированные с состоянием. На рисунке 5 приведена комбинированная диаграмма классов для всех состояний, за исключением подтверждений.
Рисунок 5. Пример диаграммы классов, показывающий видимые данные для сессии
Теперь мы можем перейти к сути вопроса, почему здесь отсутствует большое количество DTO и ассоциированных методов. На рисунке 5 показаны семь DTO с содержимым (счетчики взаимоотношений). Они абсолютно однозначно отображаются на Java-классы. Переходы в последовательности экранов, показанной на рисунке 4, отображаются на дополнительные методы OpenOrder. Возвращаемые ими DTO описываются в диаграмме классов на рисунке 5. Нам нравится использовать соглашение <TargetState>Data (вместо DTO). Параметры для этого метода показаны в виде потоков данных, ассоциированных с переходами; их имя становится частью имени метода. Некоторые примеры приведены во фрагменте кода 6:
Фрагмент кода 6. Некоторые методы только для чтения, полученные из UI
CustomerHomeData getCustomerHomeData(CustomerKey cust)
throws CustomerNotFound;
ProductCatalogData getProductData(CustomerKey cust)
throws CustomerNotFound;
ProductCatalogData getNextProductData(
CustomerKey cust,
ProductKey last
)
throws CustomerNotFound, ProductNotFound;
ProductCatalogData getPreviousProductData(
CustomerKey cust,
ProductKey first
)
throws CustomerNotFound, ProductNotFound;
OrderDetailsData getOpenOrderDetailData(
CustomerKey cust,
)
throws CustomerNotFound, OrderNotFound;
OrderDetailsData getOrderDetailData(
OrderKey order,
)
throws OrderNotFound;
OrderStatusData getOrderStatusData(
CustomerKey cust,
)
throws CustomerNotFound; |
Как можно заметить, имеется очень мало методов только для чтения. Еще меньше имеется "корневых" DTO, поскольку они используются повторно. В худшем случае для данного примера имеется всего восемь DTO, необходимых для поддержки бизнес-процесса. И даже если Вы выполнили ОО-делегирование в EJB-компоненты управления данными для загрузки полной структуры, общее число методов get<DTO>() будет относительно небольшим.
Прошу прощения за эту лекцию по общим принципам ОО-анализа и дизайна в ответ на относительно простой вопрос, но я все равно считаю, что на практике преимущества инкапсуляции, дающей возможность возвращать необходимую структуру данных, перевешивают проблемы простоты эксплуатации.
Вы согласны?
Ваш EJB Advocate
Проблема производительности, еще раз
Уважаемый EJB Advocate!
Было интересно наблюдать, как Вы выполняете объектно-ориентированный анализ и отображаете его результаты на EJB-компоненты. Ваш подход убедил меня в том, что проблема простоты эксплуатации не столь остра, как кажется. Но меня все еще одолевают мучительные сомнения, которые я не могу игнорировать.
В результате мои размышления свелись к совершенно другому вопросу: если бы не было снижения производительности при вызове методов get<attribute>() CMP, рекомендовали бы Вы использовать метод get<DTO>() в фасаде сессии, компоновщике DTO или методе Home компонента управления данными вместо простого получения необходимых атрибутов по очереди из ассоциированных логических объектов?
Например, взгляните на DetailItemData DTO на рисунке 5. Я полагаю, что если бы я последовал Вашему совету и использовал ОО-делегирование, логический объект LineItem имел бы метод getDetailItemData(). Это метод следовал бы за CMR для получения ссылки на Product. Вместо активизации getDescription() и getPrice() объекта Product мне пришлось бы создавать новый объект ProductDescriptionAndPriceData и активизировать getProductDescriptionAndPriceData(). Затем я должен был бы скопировать поля из этой структуры вместе с productId и quantity (и вычисленной суммой) в структуру DetailItemData.
Такой подход кажется мне слишком расточительным, пока производительность не падает слишком заметно.
Never Cry Wolf
Доверяйте своей интуиции, но проверяйте ее
Уважаемый Never Cry Wolf!
Ваша настойчивость заставила EJB Advocate всерьез задуматься, действительно ли его защита использования EJB-компонентов достаточно эффективна.
Я вынужден согласиться, что если нет проблем с производительностью при использовании методов get<attribute>() на локальных EJB-компонентах управления данными, Ваш подход сбора необходимых данных в фасаде или методах home или delegated компонента управления данными значительно привлекательнее. При таком подходе компилируется меньше компонентов во время компоновки и собирается меньше мусора во время исполнения, поэтому я рад, что Вы доверяете своей интуиции, подсказывающей, что в действительности ответ на вопрос не был получен. Наш диалог показывает, что иногда нужно несколько итераций, чтобы понять проблему.
С другой стороны, моя интуиция подсказывала мне, что производительность вызовов локальных методов все еще существенна. Но я не проводил никакого тестирования для проверки этой теории. Вместо этого я основывался на аксиоме: если работает - не исправляй, и не только потому, что тестирование производительности является тяжелой работой, но также потому, что изменить все мои презентационные материалы об оптимальных методиках применения и существующие примеры еще сложнее.
Эта аксиома справедлива для "традиционных" приложений, но лучше было бы проверить мою интуицию, чтобы в новых проектах разработки можно было выбрать верный подход для конкретной ситуации.
Поэтому я выполнил групповое тестирование производительности и с удивлением обнаружил, что нет значительных отличий между "клиентским" вызовом локального метода get<Attribute>() через локальный интерфейс и вызовом реализацией компонента управления данными своего собственного абстрактного метода get<Attribute>(), до тех пор пока клиент и логический объект находятся в области действия глобальной транзакции.
Получив эти новые данные, я с радостью изменю мой подход: если нет уже существующего метода get<DTO>(), предоставляющего информацию, смело используйте метод get<Attribute>() для сбора необходимых данных. Это относится к методу delegated EJB-компонента управления данными, методу Home логического объекта, фасаду сессии или (как Вы его называете) классу компоновщика DTO.
Рад также обнаружить, что есть люди, являющиеся еще большими защитниками EJB, чем я! Если мы когда-нибудь встретимся лично, я приглашу Вас на обед.
Ваш EJB Advocate
Заключение
Вот несколько интересных принципов, которые можно сформулировать на основании данной дискуссии:
- Результаты Вашего анализа должны учитывать динамические и статические аспекты как бизнес-задачи, так и пользовательского интерфейса.
- Систематически отображайте результаты Вашего анализа на соответствующие EJB-компоненты и DTO.
- Сессионные компоненты отлично подходят для реализации переходов, ассоциированных с состоянием в бизнес-процессе (обновление) или последовательности экранов (чтение).
- home-методы компонента управления данными подходят лучше всего, когда ассоциируются с объектом "шлюз", представляющим субъект actor, владеющий одним или несколькими состояниями в бизнес-процессе.
- В любом случае используйте CMR, ассоциированные с объектом-шлюзом, где это возможно, и при необходимости используйте get<DTO> (OO-делегирование) или get<Attributes> (процедурная сборка) для получения данных, которые нужно возвратить. Многое зависит от того, имеется уже соответствующий DTO или нет.
- Наконец, EJB Advocate готов признать свою неправоту. Только на это потребуется некоторое время.
Мы уверены, что Вы найдете и другие принципы. Работы должно хватить до нашей следующей встречи.
Благодарности
Отдельное спасибо Бобби Вульфу (Bobby Woolf), вдохновившему автора и предоставившему материал для данной статьи. Прочтите его блог J2EE in Practice.
Ресурсы - Примите участие в обсуждении материала на форуме.
- Оригинал статьи "The EJB Advocate: Which type of EJB component should assemble the data returned by a service?" (EN).
-
Спецификация Java Platform, Enterprise Edition (JEE) (ранее J2EE); цифра "2" была удалена, для того чтобы отделить основную концепцию Java-платформы для предприятий от конкретной версии.(EN)
- "Программирование корпоративных приложений на Java и IBM WebSphere, второе издание", Кайл Браун (Kyle Brown), Гэри Крэйг (Gary Craig), Грег Хестэр (Greg Hester), Рассел Стайнхаур (Russell Stinehour), Дэвид Питт (W. David Pitt), Марк Вайтцел (Mark Weitzel), Джим Амсден (Jim Amsden), Питер Джакаб (Peter M. Jakab), Дэниэл Берг (Daniel Berg). Предисловие Мартина Фаулера (Martin Fowler). (EN)
Об авторе  | |  |
Джефф Хэмбрик (Geoff Hambrick) является ведущим консультантом IBM Software Services для группы обеспечения WebSphere (WebSphere Enablement Team). Он живет в Раунд Рок, Техас (недалеко от Остина). Общей задачей группы обеспечения является поддержка предпродажных процессов, которая осуществляется с помощью подробного технического инструктажа и кратковременных совещаний по проверке концепций. За свою работу по созданию и распространению передового опыта для разработки приложений J2EE на базе IBM WebSphere Application Server в марте 2004 года Джефф был удостоен звания инженера с отличием IBM (IBM Distinguished Engineer). |
Выскажите мнение об этой странице
|  |