Архитектура для бизнес-объектов / уровень доступа к базе данных - PullRequest
7 голосов
/ 23 сентября 2008

По разным причинам мы пишем новую библиотеку бизнес-объектов / хранилищ данных. Одним из требований этого уровня является разделение логики бизнес-правил и фактического уровня хранения данных.

Можно иметь несколько слоев хранения данных, которые реализуют доступ к одному и тому же объекту - например, основной источник хранения данных «базы данных», который реализует большинство объектов, и другой источник «ldap», который реализует объект User. В этом сценарии пользователь может при желании поступить из источника LDAP, возможно, с немного отличающимися функциями (например, невозможно сохранить / обновить объект пользователя), но в противном случае он используется приложением таким же образом. Другим типом хранилища данных может быть веб-служба или внешняя база данных.

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

  • Бизнес-объекты - это базовые классы, а объекты хранения данных наследуют бизнес-объекты. Код клиента имеет дело с объектами хранения данных.

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

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

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

  • Бизнес-объекты инкапсулируют объекты хранения данных.

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

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

  • Бизнес-объекты - это базовые классы, объекты источника данных наследуются от бизнес-объектов. Код клиента имеет дело главным образом с базовыми классами.

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

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

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

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

Ответы [ 7 ]

11 голосов
/ 23 сентября 2008

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

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

1 голос
/ 22 мая 2010

Я обычно предпочитаю «бизнес-объект инкапсулирует объект данных / хранилище» лучше всего. Тем не менее, вкратце вы можете обнаружить высокую избыточность ваших объектов данных и бизнес-объектов, которая может показаться бесполезной. Это особенно верно, если вы выбираете ORM в качестве основы для уровня доступа к данным (DAL). Но в долгосрочной перспективе реальная отдача - это жизненный цикл приложения. Как показано, нередки случаи, когда «данные» поступают из одной или нескольких подсистем хранения (не ограничиваясь RDBMS), особенно с появлением облачных вычислений, как это обычно происходит в распределенных системах. Например, у вас могут быть некоторые данные, полученные из службы Restful, другой кусок или объект из СУБД, другой из файла XML, LDAP и т. Д. С этой реализацией это подразумевает важность очень хорошей инкапсуляции доступа к данным со стороны бизнеса. Позаботьтесь о том, какие зависимости вы выставляете (DI) через ваши c-tors и свойства.

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

Кроме того, также рассмотрите возможность управления бизнес-правилами. Если вы будете пристально смотреть на свой UML (или модель в своей голове, как я: D), вы заметите, что ваша модель бизнес-правил на самом деле другая модель, иногда даже постоянная (например, если вы используете механизм бизнес-правил) , Я хотел бы позволить бизнес-контроллеру также фактически контролировать вашу подсистему правил и позволить вашему бизнес-объекту ссылаться на правила через контроллер. Причина заключается в том, что реализации правил часто должны выполнять поиск и перекрестную проверку, чтобы определить достоверность. Часто для этого может потребоваться как поиск в гидратированных бизнес-объектах, так и поиск в базе данных. Рассмотрите возможность обнаружения дублирующихся объектов, например, когда гидратируется только «новый» объект. Оставляя ваши правила для управления вашим бизнес-контроллером, вы можете делать практически все, что вам нужно, не жертвуя этой хорошей чистой абстракцией в вашей «доменной модели».

В псевдокоде:

using(MyConcreteBusinessContext ctx = new MyConcreteBusinessContext("datares://model1?DataSource=myserver;Catalog=mydatabase;Trusted_Connection=True ruleres://someruleresource?type=StaticRules&handler=My.Org.Business.Model.RuleManager")) {

User user = ctx.GetUserById("SZE543");
user.IsLogonActive = false;
ctx.Save();
}

//a business object
class User : BusinessBase {
  public User(BusinessContext ctx) : base(ctx) {}

  public bool Validate() {
    IValidator v = ctx.GetValidator(this);
    return v.Validate();
  }
}

// a validator
class UserValidator : BaseValidator, IValidator {
 User userInstance;
 public UserValidator(User user) {
  userInstance = user;
 }

 public bool Validate() {
   // actual validation code here
   return true;
 }
}
1 голос
/ 23 сентября 2008

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

Как уже говорилось, ваш бизнес не должен подвергаться ничему, кроме вашего DTO и Фасада.

Да. Ваш клиент может иметь дело с DTO. Это идеальный способ передачи данных через ваше приложение.

0 голосов
/ 23 сентября 2008

Ну, вот я, сотрудник, которого упомянул Грег.

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

Клиентский код может не знать о хранилище данных, где хранятся бизнес-объекты, но это возможно либо в случае, когда имеется только одно хранилище данных, либо существует несколько хранилищ данных для одного и того же типа бизнес-объекта (пользователи хранятся в локальной базе данных и во внешней LDAP), но клиент не создает эти бизнес-объекты. С точки зрения системного анализа это означает, что не должно быть случаев использования, в которых наличие двух хранилищ данных объектов одного типа может повлиять на ход использования.

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

Эта ответственность может быть реализована множеством способов: это может быть объект соединения определенного типа для каждого хранилища данных; это могут быть сегрегированные методы для вызова для создания новых экземпляров BO и т. д.

С уважением,

Michael

0 голосов
/ 23 сентября 2008

CLSA существует уже давно. Однако мне нравится подход, который обсуждается в книге Эрика Эванса http://dddcommunity.org/

0 голосов
/ 23 сентября 2008

Проверьте CSLA.net Рокки Лхоткой.

0 голосов
/ 23 сентября 2008

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

...