2008-09-23 2 views
6

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ответ

10

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

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

0

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

1

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

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

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

0

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

0

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

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

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

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

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

С уважением,

Майкл

1

Я вообще предпочитаю «бизнес-объект инкапсулирует объект данных/хранения» лучше. Однако вкратце вы можете найти высокую избыточность с вашими объектами данных и вашими бизнес-объектами, которые могут показаться нецелесообразными. Это особенно верно, если вы выбираете ORM в качестве основы для вашего уровня доступа к данным (DAL). Но в долгосрочной перспективе реальная окупаемость: жизненный цикл приложения. Как проиллюстрировано, нередко «данные» поступают из одной или нескольких подсистем хранения (не ограничиваясь RDBMS), особенно с появлением облачных вычислений и, как правило, в распределенных системах. Например, у вас могут быть некоторые данные, которые поступают из службы Restful, другого фрагмента или объекта из RDBMS, другого из файла 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; 
} 
} 
Смежные вопросы