Структура бизнес-уровня, как вы строите свою? - PullRequest
3 голосов
/ 25 августа 2010

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

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

Моя обычная структура бизнес-уровня такова (базовый вид):

  • Бизнес
    • Услуги
      • FooComponent
        • FooHelpers
        • FooWorkflows
      • BahComponent
        • BahHelpers
        • BahWorkflows
    • Утилиты
      • Общие
      • ИсключенияHandlers
      • Импортеры
      • etc ...

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

XXXHelpers дают мне доступ к Save, Edit и Load соответствующих объектов, но куда я могу поместить логику для сохранения объектов с дочерними объектами.

Например:

У нас есть объекты ниже (не очень хорошие объекты, которые я знаю)

  • Employee
  • EmployeeDetails
  • EmployeeMembership
  • EmployeeProfile

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

Но я немного растерялся относительно того, куда я поместил бы эту логику и как назвать сектор, пойдет ли онпод Utilities как EmployeeManager или что-то вроде этого?

Что бы вы сделали?и я знаю, что это все предпочтения.

Более подробный макет

Рабочие процессы содержат все вызовы непосредственно в DataRepository, например:

public ObjectNameGetById(Guid id)
{
    return DataRepository.ObjectNameProvider.GetById(id);
}

А затем помощникидоступ провайдера к рабочим процессам:

public ObjectName GetById(Guid id)
{
    return loadWorkflow.GetById(id);
}

Это сокращает дублирующийся код, поскольку вы можете иметь один вызов в рабочем процессе для getBySomeProperty, а затем несколько вызовов в помощнике, которые могут выполнять другие операции и возвращатьданные по-разному, плохим примером будут публичные GetByIdAsc и GetByIdDesc

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

projectName.Core

projectName.Business
    - Interfaces
        - IDeleteWorkflows.cs
        - ILoadWorkflows.cs
        - ISaveWorkflows.cs
        - IServiceHelper.cs
        - IServiceViewHelper.cs
    - Services
        - ObjectNameComponent
            - Helpers
                - ObjectNameHelper.cs
            - Workflows
                - DeleteObjectNameWorkflow.cs
                - LoadObjectNameWorkflow.cs
                - SaveObjectNameWorkflow.cs
    - Utilities
        - Common
            - SettingsManager.cs
            - JavascriptManager.cs
            - XmlHelper.cs
            - others...

        - ExceptionHandlers
            - ExceptionManager.cs
            - ExceptionManagerFactory.cs
            - ExceptionNotifier.cs


projectName.Data
    - Bases
        - ObjectNameProviderBase.cs
    - Helpers
        - ProviderHelper.cs
    - Interfaces
        - IProviderBase.cs
    - DataRepository.cs

projectName.Data.Model
    - Database.edmx

projectName.Entities (Entities that represent the DB tables are created by EF in .Data.Model, this is for others that I may need that are not related to the database)
    - Helpers
        - EnumHelper.cs

projectName.Presenation

(зависит от вызова приложения)

projectName.web
projectName.mvc
projectName.admin

Тестовые проекты

projectName.Business.Tests
projectName.Data.Test

Ответы [ 2 ]

3 голосов
/ 26 августа 2010

+ 1 за интересный вопрос.

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

Но сначала, мой предпочтительный подход здесь - это довольно распространенная корпоративная архитектура, которую я постараюсь кратко осветить, но там гораздо больше глубины. Это требует некоторых радикальных изменений в мышлении - использование NHibernate или Entity Framework, чтобы позволить вам напрямую запрашивать объектную модель и позволять ORM решать такие вещи, как сопоставление с базой данных и из нее, ленивые отношения загрузки и т. Д. Это позволит вам реализовать вся ваша бизнес-логика в доменной модели.

Первые уровни (или проекты в вашем решении);

YourApplication.Domain

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

YourApplication.Data

Репозитарий классов - это классы, которые имеют дело с получением совокупного корня (ов) вашей доменной модели.

Например, в ваших примерах классов маловероятно, что вы захотите взглянуть на EmployeeDetails, не обращая внимания и на Employee (я знаю, что вы знаете, суть строки счета-фактуры - лучший пример, вы обычно получаете счет-фактуру) линии через счет, а не загружая их самостоятельно). Таким образом, классы репозитория, из которых у вас есть один класс на корень агрегата, будут отвечать за извлечение исходных сущностей из базы данных с помощью рассматриваемого ORM, реализацию любых стратегий запросов (таких как разбиение на страницы или сортировку) и возврат корня агрегата в потребитель. Хранилище будет использовать текущий активный контекст данных (ISession в NHibernate) - способ создания этого сеанса зависит от типа приложения, которое вы создаете.

YourApplication.Workflow

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

Другие уровни зависят от вашей архитектуры и приложения, которое вы реализуете.

YourApplication.YourChosenPresentationTier

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

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

Если вам не нужно распространять свои уровни, помните, что первое правило распределенных архитектур - не распространять, тогда вы будете использовать рабочий процесс / службы и репозитории непосредственно из asp.net, mvc, wpf, winforms и т. Д.

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

В настольном приложении, WPF или winforms у вас будет контекст для каждой формы. Это гарантирует, что изменения в сущностях домена в диалоговом окне редактирования, которые обновляют модель, но не вносят ее в базу данных (например, было выбрано «Отмена»), не мешают другим контекстам или, что еще хуже, случайно сохраняются.

Зависимость инъекций

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

Те пространства имен

Наконец, причина, по которой я потеряю пространство имен помощников, заключается в том, что в приведенной выше модели они вам не нужны, но также, как и пространства имен утилит, они дают ленивым разработчикам повод не думать о том, где фрагмент кода логически сидит. MyApp.Helpers. * И MyApp.Utility. * Просто означает, что если у меня есть какой-то код, скажем, обработчик исключений, который может быть логически принадлежит MyApp.Data.Repositories.Customers (может быть, ссылка клиента не является уникальным исключением), ленивый Разработчик может просто поместить его в MyApp.Utility.CustomerRefNotUniqueException, не задумываясь.

Если у вас есть общий код типа платформы, который нужно обернуть, добавьте проект MyApp.Framework и соответствующие пространства имен. Если вы добавляете новое связующее звено модели, поместите его в MyApp.Framework.Mvc, если это обычная функция ведения журналов, поместите его в MyApp.Framework.Logging и так далее. В большинстве случаев не нужно вводить пространство имен служебных программ или помощников.

Завершение

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

Приветствие Tony

0 голосов
/ 31 августа 2010

На этой странице есть хорошая схема и описание макета приложения, хотя далее мы рассмотрим статью, в которой приложение не разбито на физические уровни (отдельный проект) - Entity Framework POCO Repository

...