Уровень бизнес-логики и уровень доступа к данным: круговая зависимость - PullRequest
23 голосов
/ 19 января 2009

У меня небольшая проблема с архитектурой. В моем проекте у меня есть уровень бизнес-логики (BLL), который содержит все мои бизнес-правила, модели и OO API для интерфейса. Каждый объект имеет статические методы, такие как getById, которые возвращают экземпляр указанного объекта. У каждого объекта также есть методы, такие как save и, delete. Это очень простой код OO.

Теперь у меня есть слой DataAccess (DAL), содержащийся в отдельном пространстве имен, для каждого объекта BLL у меня есть DataClass или «Репозиторий», который выполняет команды getById и save. Таким образом, методы BLL save и getById представляют собой тонкий слой вокруг методов DataClass.

public static NewsItem GetByID(int id)
{
       return DataFactory.GetNewsItemRepository().GetNewsItemById(id);
}

Чтобы DataClasses возвращали объекты BLL, им нужно знать BLL. так что теперь у нас есть:

GUI ---> BLL <----> DAL

DataFactory возвращает только объекты, которые реализуют Интерфейс, поэтому я могу скрыть детали реализации, такие как «OracleNewsItemRepository».

Но теперь из-за того, что беспокоило меня с тех пор, как я начал объектно-ориентированное программирование. В моем текущем решении и BLL, и DAL должны знать друг друга. Это циклическая зависимость, и лучше избегать циклических зависимостей. Также я хочу показать только интерфейсы (и мою DataFactory), а не мои классы. Это можно сделать, поместив слой DAL в отдельную сборку. Что имело бы смысл. Однако Visual Studio не позволяет двум сборкам ссылаться друг на друга. Еще один вопрос по этому поводу: C # внутренние модификаторы доступа

Почему-то мне кажется, что я неправильно понял всю схему доступа к данным. Такое ощущение, что я сворачиваю шаблон ActiveRecord с другими вещами, такими как DataMappers. Я провел много времени на сайте Мартина Фаулера, но эти шаблоны описаны очень обобщенно и проиллюстрированы очень абстрактной UML-диаграммой.

Они не решают мою проблему. Может быть, я немного анальный, и не существует такой вещи, как «идеальный шаблон доступа к данным». И то, что я делаю сейчас, не кажется ужасно неправильным. Но, как я делаю вещи сейчас, кажется, не в порядке ...

Есть идеи?

Ответы [ 8 ]

12 голосов
/ 19 января 2009

Я думаю, что ваш шаблон доступа к данным в порядке. Чего вы не делаете, так это связывает свой BLL с OracleDAL. Вы подключаетесь к интерфейсам DAL. Определенная доля связи абсолютно необходима, иначе вы ничего не сможете сделать.

Я предполагаю, что ваши классы DataFactory и INewsItemRepository существуют вне вашего уровня DAL. Ниже приведен пример организации моих решений. Я не использую ActiveRecord, поэтому это может вас не устраивать.

Core (Project)
  Domain
    Business Entities
  Data
    Repository Interfaces
    **Your DataFactory**

OracleData (Project)
  Data
    Oracle Repository Implementations

SqlData (Project)
  Data
    Sql Repository Implementations

UI (Project)

Надеюсь, это поможет.

11 голосов
/ 19 января 2009

На мой взгляд:

Уровень доступа к данным (DAL) должен работать с POCO (простыми старыми объектами CLR), используя такие операции, как: SaveNewsItem ( NewsItemDAO newsItemDAO ). POCO - это ваши DAO (объекты доступа к данным).

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

DAL вообще не должен знать о уровне бизнес-логики. Теоретически, он должен иметь возможность звонить с любого клиента. Например, что если вы хотите отделить DAL от приложения и развернуть его как отдельную службу, выставляя себя через WCF?

Как уже упоминалось, операции DAL, например, Доступ к SaveNewsItem должен осуществляться BO через интерфейсы, возможно, через внедрение зависимостей / IoC.

5 голосов
/ 19 января 2009

Вы можете использовать интерфейсы / внедрение зависимостей для решения вашей проблемы.

Ваш бизнес-уровень (BL) содержит интерфейсы доступа к данным (DA), которые должен реализовывать (возможно, более одного) DAL. Проекты DAL имеют ссылки на проекты BL, так что они могут выплевывать бизнес-объекты (BO) и реализовывать интерфейсы DA.

Ваши BO могут вызывать DataFactory, которая может создавать экземпляр объекта DA посредством внедрения или отражения зависимостей.

Я использовал этот шаблон во многих наших приложениях здесь, на работе (как в Интернете, так и в smart-клиенте), и он прекрасно работает.

3 голосов
/ 26 февраля 2012

Сейчас это немного устарело, но, возможно, вам следует подумать о том, чтобы поместить pocos / interfaces в другую сборку.

Project.Data references Project.Entities
Project.BL references Project.Entities and Project.Data
Project.UI references Project.Entities and Project.BL

Здесь нет циклических ссылок.

2 голосов
/ 19 января 2009

IceHeat, пример @Craig Wilson имеет смысл, и его , вероятно, , полученный из этой статьи: http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx.

Это ХОРОШО стоит прочитать и занимается разработкой, управляемой доменом, которая решает проблемы, с которыми вы здесь сталкиваетесь. Я рекомендую его всем, даже если вы не рассказываете обезьянам о NHibernate, это отличная статья.

2 голосов
/ 19 января 2009

Просто чтобы прояснить, мне нравится думать о бизнес-модели и бизнес-логике как о двух отдельных слоях. Ваша бизнес-модель - это ваши POCO (простые старые объекты CLR). Ваш уровень бизнес-логики будет нести ответственность за выполнение проверок, транзакций и т. Д. С использованием как вашей бизнес-модели, так и интерфейса с вашим DAL, который может быть подключен несколькими способами (Spring, Castle или ваш собственный IoC-контейнер собственного производства).

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

1 голос
/ 19 января 2009

Я бы удалил любой метод Get () и Save () из вашей BLL (модель предметной области) .. вот что я бы сделал

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

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

Вот хорошая статья на ту же тему ... Воссоздание объектов

Прочтите комментарий Деяна Петрова о том, как использовать динамический прокси

0 голосов
/ 19 января 2009

DAL должен быть абстрактным, поэтому он должен содержать только простые объекты ADO.NET, которые взаимодействуют с внутренней базой данных, например, соединение DataAdapter, DataReader и т. Д. Имея это под рукой, вы можете ссылаться на DAL на своем уровне Biz, а когда дело доходит до ваших сущностей с небольшой абстракцией, вы можете решить все свои проблемы, например, если у вас есть класс клиента, вы можете создать класс клиента abstaractoin, который реализует базовые операции для взаимодействия с DAL, такие как сохранение, обновление и извлечение данных, а также в другом классе, который наследует класс абстракции, переопределяют реализацию методов базового класса в соответствии с проверкой Biz и т. д.

...