UnitOfWork нарушает принцип Single Responsibility?
От: Docker Канада  
Дата: 14.11.13 07:07
Оценка:
Коллеги, поделитесь мнением и мудростью!

Не нарушает ли Фаулеровское определение Unit Of Work принцип Single Responsibility из принципов ООД сформулированных Р. Мартином еще лет 20 назад. Вопрос абсолютно не о сферических конях в вакууме, конкретную проблему смотрите ниже.

Немного теории

У Фаулера UoW определяется как:

"Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems."

У Мартина Single Responsibility:
"A class should have one, and only one, reason to change."

Т.е. получается, если слепо следуем Фоулеру, нарушаем принцип Мартина, так как если меняется метод отслеживания изменений — меняем UofW, если меняется координация записывания изменений — опять меняем UoW.

Пример из практики

Смотрим на взаимодействие репозитория и Unit Of Work. Пусть у нас есть один репозиторий реализующий IUserRepository, который может работать с каким-то хранилищем данных (база, мок объекты, файловая система, компонента написанная PupkinSoft Inc., неважно). Ну, и допустим мы хотим сделать такое отслеживание изменений о котором пишет Фаулер.

Внимание вопрос, если какая-то из реализаций репозитория уже делает “list of objects affected by a business transaction”, зачем мне еще раз это реализовывать в UnitOfWork? Но Фаулер это жестко запихивает в UnitOfWork. Это на самом порождает еще больше проблем. Например если я отслеживаю изменения в UnitOfWork, то если я меняю данные, а потом зачитываю новые данные, то кто-то еще должен проверить не содержатся ли зачитанные данные в списке измененных и т.д.

Чешем затылок, мыслим по Мартину. По нему должны быть классы которые:

1. Coordinates the writing out of changes and the resolution of concurrency problems (IUnitOfCoordinationWork)
2. Repository (чтобы он там не делал, не о нем вопрос) (IUserRepository)
3. Maintains a list of objects affected by a business transaction (реализует ITrackChanges)

Тогда все просто и красиво.

1. UnitOfWork реализует IUnitOfCoordinationWork.
2. Методы хранилища реализуют IRepository
3. Если конкретная реализация репозитория реализует “list of objects affected by a business transaction” то оборачиваем эту функциональность в ITrackChanges, если нет, то пишем сами. Т.е. если функциональность уже есть в репозитории, то не лопатим тонны кода делающего тоже самое в UnitOfWork, изобретая велосипед, как это было если б делали по Фаулеру, а используем готовое.


Да и вообще, но это другая тема, “Maintains a list of objects affected by a business transaction” может быть нафиг не нужна на многих проектах. Зачем добавлять это требование в такой “краеугольный камень” как UnitOfWork?

Вот такие мысли. Поскольку я “замахнулся” на великого Фаулера, то мне интересно, что думаете вы.

Спасибо!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.