Как управлять связью между уровнями домена и базы данных?

StackOverflow https://stackoverflow.com/questions/549305

Вопрос

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

Разъяснение Мое существующее решение использует Data Mappers для непосредственного взаимодействия с базой данных.Однако по мере дальнейшего изучения этой проблемы многие люди предположили, что уровень домена не должен напрямую взаимодействовать с преобразователями данных, которые фактически выполняют взаимодействие с базой данных, и не содержать их.Вот почему я поместил объекты репозитория между доменом и необходимыми преобразователями данных, но это не кажется вполне естественным и правильным.Итак, реальный вопрос заключается в том, какой уровень естественно существует для обеспечения связи между доменом и картографами данных?Любые примеры того, как его структурировать, будут оценены по достоинству.

Например:

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

Решение

Габриэль, это называется "проблема согласования импедансовСуществует множество решений: от таких тяжеловесных, как J2EE-компоненты управления данными, до Ruby ActiveRecord и простого программирования ручного соединения.

Обновлять

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

Любая из этих архитектурных проблем обусловлена ​​нефункциональными требованиями, такими как производительность;кроме того, здесь возникает проблема с корректностью: вы хотите убедиться, что обновления выполняются в правильном порядке.Итак, вам нужно будет подумать о нагрузка, то есть шаблон использования в реальных приложениях.Имея это в виду, у вас в основном есть несколько проблем:во-первых, базовые типы данных в вашем приложении могут неправильно сопоставляться с базой данных (например, какое свойство VARCHAR представлено в вашем коде?), а во-вторых, ваша модель предметной области может некорректно сопоставляться с моделью вашей базы данных.

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

Теперь, если вы полностью контролируете свою модель базы данных, это несколько упрощает ситуацию, потому что тогда вы можете сделать свою модель базы данных более похожей на домен.Это может означать, что модель базы данных несколько денормализована, но если это так, вы можете (в зависимости от вашей базы данных) справиться с этим с помощью представлений или просто не иметь полностью нормализованной базы данных.Нормализация — полезная теоретическая конструкция, но это не значит, что ее нельзя ослабить в реальной системе.

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

В этот момент, однако, вы сталкиваетесь с проблемами «Не повторяйся» и «Сделай самую простейшую вещь, которая может работать». Подумайте о том, что наиболее вероятно изменится?Ваша доменная модель?Если у вас сильная доменная модель, это менее вероятно — бизнес меняется относительно редко.Точное представление данных в базе данных?Немного более распространенный.Или, чаще всего, точные шаблоны использования (например, обнаружение необходимости обработки одновременных обновлений). Итак, если вы подумаете об этом, что вам нужно сделать, чтобы максимально упростить работу с наиболее распространенными изменениями.

Я понимаю, что это не дает вам очень точных инструкций, но я не думаю, что мы можем предложить точные инструкции, не зная многого о вашем применении.Но у меня также создается впечатление, что вы задаетесь вопросом, каким будет «правильный» способ справиться с этим, в то время как вы уже работаете с чем-то, что более или менее выполняет свою работу.Итак, я бы спросил: «Чем ты сейчас недоволен?» и "Как бы вы хотели решить это?"

Другие советы

Существует различие между моделью предметной области и ее реализацией.Просто потому, что ваша модель показывает взаимосвязь Person ---> Campaign ---> Event не означает, что вы должны реализовать это таким образом.IOW, ваша модель показывает ваш анализ и проектирование объектно-ориентированным способом, но вы реализуете эту модель в ООП, который ограничен в том, насколько хорошо она может воспроизвести эту модель в коде.

Рассмотрим следующее.

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

Что касается связи между доменом и уровнями персистентности, рассматривайте их как две совершенно разные системы, не связанные друг с другом.Все, что каждый из них знает, — это то, каковы его обязанности и какие объявления он делает.Например, уровень сохранения знает, как сохранить переданные ему данные и объявить, что данные сохранены.Однако уровень персистентности не обязательно должен понимать объекты предметной области.Аналогично, доменный уровень понимает Person, Campaign, и Event но ничего не знает о настойчивости.

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

Итак, в коде (псевдо-C#)...

namespace DomainLayer
{
    interface IDomainListener 
    {
        void PersonCreated(Person person);
    }

    class Person
    {
        private string name;

        public Person(string name)
        {
            this.name = name;
        }

        public string Name
        {
            get { return name; }
        }
    }

    class Domain 
    {
        private IDomainListener listener;

        public Domain(IDomainListener listener) {
            this.listener = listener;
        }

        public void CreatePerson(string name) {
            Person person = new Person(name);
            listener.PersonCreated(person);
        }
    }
}


namespace PersistenceLayer
{
    interface IPersistenceListener
    {
        void PersonDataSaved(int id, object data);
    }

    class Persistence
    {
        private IPersistenceListener listener;

        public Persistence(IPersistenceListener listener) 
        {
            this.listener = listener;
        }

        public void SaveData(object data)
        {
            int id = ...; // save data and return identifier
            listener.DataSaved(id, data);
        }
    }
}

namespace MyApplication
{
    class MyController : IDomainListener, IPersistenceListener
    {
        public void CreatePersonButton_Clicked()
        {
            Domain domain = new Domain(this);
            domain.CreatePerson(NameTextbox.Text);
        }

        public void PersonCreated(Person person)
        {
            Persistence persistence = new Persistence(this);
            persistence.SavePersonData(person.Name);
        }

        public void DataSaved(int id, object data)
        {
            // display data on UI
        }
    }   
}

Как видите, пространства имен представляют разные уровни.А XYZListener интерфейсы определяют объявления, которые делаются XYZ уровень.Любые другие уровни, которые заинтересованы в этих объявлениях и будут реагировать на них, должны реализовать эти интерфейсы, как это делает наш MyApplication уровень.

При нажатии кнопки «Создать» контроллер создает Domain фасадный объект для уровня домена и регистрируется в качестве прослушивателя.Затем он вызывает CreatePerson метод, который создает экземпляр Person затем объявляет, что это было сделано, передавая новый экземпляр.Контроллер отвечает на это объявление в PersonCreated реализация, в которой он создает фасад уровня персистентности и снова регистрируется в качестве прослушивателя.Затем он вызывает SaveData метод, который объявляет DataSaved когда завершено.Реализация этого метода затем отображает данные в пользовательском интерфейсе.

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

Возвращаясь к вашей конкретной проблеме, у вас может быть метод FindPerson о настойчивости, которая бы объявила PersonFound(int id).Ответом контроллера будет вызов уровня персистентности для получения данных о кампании и событиях, а затем вызов уровня домена с этими данными для построения Person.

Извините за длинный ответ...

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

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

Я бы посмотрел на уровни абстракции данных, используемые PHPCake и Symfony.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top