Технология отделения от доменных объектов - PullRequest
0 голосов
/ 12 декабря 2011

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

Вот что мы считаем существительными наших доменных имен:

  • Тест (т. Е. Объем крови, контроль качества)
  • Пациент
  • Образец (т. Е. Что-то для подсчета)
  • Спектр
  • Контекст выполнения теста (т. Е., спецификация образцов и их порядок, соответствующий определенному типу теста)

Мы считаем, что наши доменные глаголы:

  • Перемещение карусели в заданную позицию
  • Получение спектра (т. Е. Подсчет выборки)
  • Выполнение тестов

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

Специфическими технологиями, которые вызывают у нас некоторую путаницу, являются Prism и WCF.

(1) Prism использует агрегатор событий для передачи не-CLR событий по системе.Контроллер выполнения теста использует это, чтобы сообщить другим частям системы, что происходит (например, подсчитывается образец 2А, для текущего теста осталось 34 минуты).Технически, агрегатор событий - это технология , которая является частью Prism, и доменные объекты / сервисы не должны полагаться на технологию.

Вопрос : есть ли способреструктурировать вещи таким образом, чтобы наша служба домена не зависела от технологии?

(2) У нас есть две службы WCF, которые позволяют нам взаимодействовать с устройством смены образцов и гамма-счетчиком.У каждой службы есть контракт (т. Е. Интерфейс, украшенный атрибутами, специфичными для WCF).По крайней мере, с контрактами мы разделяем опасения так, что наше основное применение зависит от поведения , а не от конкретного устройства смены образцов или гамма-счетчика.Однако WCF - это технология , и код приложения должен знать, что эта служба, с которой мы говорим, является службой WCF (что делается путем создания прокси-класса).Чтобы удовлетворить ограничения DDD, мы получаем несколько классов / интерфейсов с одинаковыми именами, которые кажутся избыточными.Вот пример

  • IGammaCounterService - контракт WCF, который определяет методы для связи с гамма-счетчиком.На этот интерфейс ссылаются (1) сторона WCF, в которой живет фактическая реализация, и (2) код приложения, который обращается к этой службе.
  • IGammaCounter - набор свойств / методов, определяющих поведение длягамма-счетчик(Это часть нашего домена.)
  • GammaCounterProxy - класс, реализующий контракт на обслуживание WCF.Это то, что наше приложение использует для связи со службой WCF.
  • GammaCounter - класс, который используется бизнес-логикой.Это GammaCounterProxy (через наследование), а также реализует IGammaCounter.(Примечание: мы используем инверсию контейнера управления - в частности, Unity - для регистрации этого экземпляра в нашем приложении.)

Вопрос : У нас есть интерфейсы в домене и в WCFсторона, которая в основном имеет одинаковые имена методов.Есть ли лучший / более чистый способ сделать это?

Ответы [ 2 ]

2 голосов
/ 12 декабря 2011

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

  • один или несколько транспортов (например, TCP, HTTP, Named Pipes, MSMQ)
  • один или несколько форматов кодирования (двоично-кодированный-XML, XML, JSON)
  • ноль или более других проблем (например, поддержка WS- *)

Например, в моем примере Magic8Ball WCF я предоставляю сервис Magic8Ball одновременно через несколько конечных точек: двоичный XML / TCP для (очень) быстрого доступа от клиентов WCF, XML / HTTP для не-WCF клиенты, JSON / HTTP для клиентов REST.

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

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

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

0 голосов
/ 13 декабря 2011

Дополнительной осью структуры, которую следует учитывать в решении, является набор прикладных уровней. Например, кажется, что в этом случае у вас есть уровень представления (реализованный с использованием Prism / WPF), уровень обслуживания (реализованный WCF) и уровень бизнеса / домена (реализованный с использованием DDD).

Есть ли способ реструктурировать вещи так, чтобы наш доменный сервис не технологии зависит?

Если контроллер выполнения теста является контроллером в смысле MVC, то он не должен содержать бизнес-логику. Вместо этого его работа заключается в координации взаимодействия между пользовательским интерфейсом и бизнес-уровнем. В этом конкретном случае контроллер должен направлять команды на бизнес-уровень через уровень обслуживания, реализованный в WCF. Однако сам контроллер является частью уровня представления, и поэтому тот факт, что он зависит от конкретного технологического компонента, такого как агрегатор событий, не является проблемой, поскольку вы уже выбрали WCF / Prim в качестве технологии для уровня представления - нет смысла абстрагироваться, особенно преждевременно.

У нас есть интерфейсы в домене и на стороне WCF, которые в основном имеют одинаковые имена методов. Есть ли лучший / более чистый способ сделать это?

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

Что касается организации решений, у вас есть несколько вариантов. Один из них - полностью скрыть уровень домена от уровня представления и разрешить доступ к нему только через уровень обслуживания. Таким образом, проект уровня представления (WPF / Prism) будет ссылаться на тонкий проект, который содержит контракт на обслуживание и связанные контракты на данные (DTO). Это может быть небольшой проект, который определяет «схему» вашего сервисного уровня. На этот проект также будет ссылаться проект WCF, который реализует контракт на обслуживание. Преимущество этого подхода состоит в том, что домен полностью инкапсулирован уровнем обслуживания. Вы можете изменить реализацию контракта на обслуживание, повторно развернув свой сервис - не нужно также повторно развертывать уровень представления. Недостатком является то, что это может быть излишним или может не подходить для домена, чтобы быть представленным в качестве службы.

Кроме того, меня немного смущают ваши соглашения об именах и структура. Например, GammaCounterProxy не является прокси, прокси создается WCF, когда вы получаете ссылку на сервисный контракт IGammaCounterService. Сам класс, реализующий сервис, является просто реализацией, а не прокси. Кроме того, для GammaCounter кажется неправильным наследовать от GammaCounterProxy. Для GammaCounter было бы разумнее напрямую реализовать IGammaCounter и использовать этот объект в GammaCounterProxy (переименованном во что-то вроде GammaCounterImpl). Работа GammaCounterImpl заключается в обработке некоторой команды (представленной параметрами DTO). Это будет сделано путем загрузки всех соответствующих объектов домена, таких как GammaCounter, вызова методов для них, а затем, возможно, возврата результата (в виде DTO), который затем будет обработан на уровне представления.

...