Ответ 1
Причина
Корень вашей проблемы - неправильное использование активной записи. AR предназначен для простых объектов домена только с базовыми операциями CRUD. Когда вы начинаете добавлять большую логику проверки и отношения между несколькими таблицами, шаблон начинает разрываться.
Активная запись в лучшем случае является незначительным нарушением SRP для простоты. Когда вы начинаете накапливать обязанности, вы начинаете налагать суровые наказания.
Решение (s)
Уровень 1:
Лучшим вариантом является отдельная логика бизнеса и хранения. Чаще всего это делается с помощью объекта домена и data mappers:
-
Объекты домена (в других материалах, также известных как объекты бизнес-объекта или объекта модели домена) имеют дело с проверкой и конкретными бизнес-правилами и совершенно не знают, как (или даже "если" ) данные в них сохранялись и извлекались. Они также позволяют иметь объект, который не связан непосредственно с структурами хранения (например, таблицами БД).
Например: у вас может быть объект домена
LiveReport
, который представляет текущие данные о продажах. Но в БД он может не иметь конкретной таблицы. Вместо этого он может обслуживаться несколькими картографами, которые собирают данные из Memcache, базы данных SQL и некоторого внешнего SOAP. А логика экземпляраLiveReport
полностью не связана с хранилищем. -
Датчики данных знают, куда помещать информацию из объектов домена, но они не проверяют целостность данных или проверку целостности данных. Мысль, что они могут обрабатывать исключения, которые конусы от абстракций хранения низкого уровня, например, нарушение ограничения
UNIQUE
.Датчики данных также могут выполнять транзакцию, но если для нескольких объектов домена требуется выполнить одну транзакцию, вы должны добавить, чтобы добавить Единицу работы (подробнее об этом ниже).
В более сложных/сложных случаях карты данных могут взаимодействовать и использовать DAOs и построители запросов. Но это больше для ситуации, когда вы пытаетесь создать ORM-подобную функциональность.
Каждый объект домена может иметь несколько картографов, но каждый обработчик должен работать только с определенным классом объектов домена (или подклассами одного из них, если ваш код придерживается LSP). Вы также должны признать, что объект домена и коллекция объекта домена являются двумя отдельными предметами и должны иметь отдельные сопоставления.
Кроме того, каждый объект домена может содержать другие объекты домена, точно так же, как каждый преобразователь данных может содержать другие картотеки. Но в случае картографов это гораздо больше зависит от предпочтения (я не люблю его яростно).
Другим усовершенствованием, которое могло бы облегчить ваш текущий беспорядок, было бы предотвращение протекания логики приложения на уровне презентации (чаще всего - контроллер). Вместо этого вы в значительной степени выиграете от использования служб, которые содержат взаимодействие между mappers и объектами домена, создав таким образом API-интерфейс public-ish для вашего модельного слоя,
В основном, сервисы, которые вы инкапсулируете полными сегментами вашей модели, которые могут (в реальном мире - с небольшими усилиями и настройками) повторно использоваться в разных приложениях. Например: Recognition
, Mailer
или DocumentLibrary
будут все службы.
Кроме того, я думаю, что не должен, что не все службы должны содержать объект и карты домена. Хорошим примером может служить ранее упомянутый Mailer
, который может использоваться либо напрямую контроллером, либо (что более вероятно) другой службой.
Уровень 2:
Если вы перестанете использовать шаблон активной записи, это станет довольно простой проблемой: вам нужно убедиться, что вы сохраняете только данные из этих объектов домена, которые фактически изменились с момента последнего сохранения.
Как я вижу, есть два способа приблизиться к этому:
-
Quick'n'Dirty
Если что-то изменилось, просто обновите все это...
То, что я предпочитаю, - это ввести переменную
checksum
в объекте домена, которая содержит хэш из всех переменных объекта домена (конечно, за исключениемchecksum
it self).Каждый раз, когда картографу предлагается сохранить объект домена, он вызывает метод
isDirty()
на этом объекте домена, который проверяет, изменились ли данные. Тогда картограф может действовать соответствующим образом. Это также с некоторыми настройками можно использовать для графиков объектов (если они не являются обширными, и в этом случае вам может понадобиться рефакторинг в любом случае).Кроме того, если ваш объект домена фактически сопоставляется с несколькими таблицами (или даже с разными формами хранения), может быть разумным иметь несколько контрольных сумм для каждого набора переменных. Так как сборщик уже написан для конкретных классов объекта домена, это не укрепит существующую связь.
Для PHP вы найдете несколько примеров кода в этом ansewer.
Примечание:, если ваша реализация использует DAO для изоляции объектов домена от карт данных, тогда логика проверки на основе контрольной суммы будет перенесена в DAO.
-
Это "отраслевой стандарт" для вашей проблемы, и есть целая глава (11), посвященная этому в книге PoEAA.
Основная идея заключается в том, что вы создаете экземпляр, который действует как контроллер (в классическом, а не в смысле MVC слова) между вами объектами домена и данными.
Каждый раз, когда вы изменяете или удаляете объект домена, вы сообщаете об этом подразделению. Каждый раз, когда вы загружаете данные в объект домена, вы запрашиваете Unit of Work для выполнения этой задачи.
Есть два способа сообщить Unit of Work об изменениях:
- регистрация вызывающего абонента: объект, который выполняет изменение, также информирует Отдел работы
- регистрация объекта: измененный объект (обычно из сеттера) информирует Единицу работы, что она была изменена.
Когда все взаимодействие с объектом домена завершено, вы вызываете метод
commit()
в Единице работы. Затем он находит необходимые карты и сохраняет все измененные объекты домена.
Уровень 3:
На этом этапе сложности единственной жизнеспособной реализацией является использование Единицы работы. Он также будет отвечать за инициирование и совершение транзакций SQL (если вы используете базу данных SQL) с соответствующими предложениями отката.
P.S.
Прочитайте книгу "Шаблоны архитектуры корпоративных приложений". Это то, что вам отчаянно нужно. Он также исправит неправильное представление о шаблонах дизайна MVC и MVC, которые вы приобрели с помощью Rails-подобных фреймворков.