Разбираем паттерны: Active Record

Последнее время я изучаю паттерны проектирования и архитектурные подходы, и постепенно начинаю замечать, что многие вещи, которыми я давно пользуюсь в Laravel, имеют вполне конкретные названия.

Один из таких паттернов — Active Record.

Если коротко, идея Active Record заключается в том, что объект одновременно представляет данные из базы и умеет работать с этой базой.

Именно такой подход используется в Eloquent ORM в Laravel.

Как это выглядит в Laravel

Например, у нас есть модель пользователя:

class User extends Model
{
}

Получить пользователя и изменить его можно непосредственно через модель:

$user = User::find(10);
 
$user->name = 'John';
$user->save();

Здесь User отвечает сразу за несколько вещей: представляет пользователя, содержит его данные и предоставляет методы для работы с базой данных — find(), save(), delete() и т.д.

Получается примерно такая схема:

User
├── данные пользователя
├── бизнес-логика
└── работа с БД

В этом и заключается основная идея Active Record.

Active Record vs Data Mapper

Другой распространённый подход — Data Mapper. Здесь объект предметной области не должен знать, как он сохраняется в базе.

Условно код будет выглядеть так:

$user = $userRepository->findById(10);

$user->changeName('John');

$entityManager->flush();

Здесь User отвечает за данные и поведение, а отдельный механизм — Repository/EntityManager/Data Mapper — занимается сохранением в БД.

То есть:

Active Record:

User
├── данные
└── работа с БД


Data Mapper:

User
└── данные и поведение

Data Mapper / EntityManager
└── работа с БД

В PHP хорошим примером Data Mapper является Doctrine ORM, который часто используется в Symfony.

Где здесь плюсы и минусы?

Главное преимущество Active Record — простота. Для обычных CRUD-приложений очень удобно написать:

$product = Product::find($id);
 
$product->price = 100;
$product->save();

Не нужно создавать дополнительные классы и абстракции.

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

Поэтому в Laravel часто используют Eloquent вместе с Service Layer, Repository и другими паттернами, распределяя ответственность между несколькими слоями.

В итоге я бы сформулировал разницу так:

Active Record — объект знает, как сохранить себя.
Data Mapper — объект не знает, как он сохраняется.

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

Добавить комментарий

CAPTCHA
Защита от спама
Target Image