Структура бизнес-уровня, как вы строите свой?


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

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

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

  • бизнес
    • услуги
      • Фоокомпонент
        • FooHelpers
        • FooWorkflows
      • Бахкомпонент
        • BahHelpers
        • BahWorkflows
    • утилиты
      • общие
      • ExceptionHandlers
      • импортеры
      • и т. д...

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

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

Например:

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

  • сотрудник
  • 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 а затем несколько вызовов в помощнике, который может выполнять другие операции и возвращать данные по-разному, плохим примером будет public GetByIdAsc и GetByIdDesc

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

Имя проекта.Ядро

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

Имя проекта.Presenation

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

projectName.web
projectName.mvc
projectName.admin

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

projectName.Business.Tests
projectName.Data.Test
2 2

2 ответа:

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

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

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

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

Ваше обращение.Домен

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

Ваше обращение.Данные

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

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

Ваше обращение.Рабочий процесс

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

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

Ваше обращение.YourChosenPresentationTier

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

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

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

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

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

Инъекция зависимостей

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

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

Наконец, причина, по которой я бы потерял пространство имен помощников, заключается в том, что в модели выше они вам не нужны, но также, как и пространства имен утилит, они дают ленивым разработчикам повод не думать о том, где кусок кода логически сидит. Мой друг.Прислуга.* и MyApp.Полезность.* просто означает, что если у меня есть какой-то код, скажем обработчик исключений, который, возможно, логически принадлежит MyApp.Данные.Хранилища.Клиенты (возможно, это клиент ref не является уникальным исключением), ленивый разработчик может просто разместить его в MyApp.Полезность.CustomerRefNotUniqueException без необходимости действительно думать.

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

Завернуть

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

Ура! Тони

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