Практика ООП (Оценка: +1)

Печать / RSS-лента
Я не приверженец практики без теории, потому постараюсь попутно сопровождать весь код важной для незнакомых с ОО архитектурой информацией.
И так хочется продемонстрировать вам мое решение тривиальной ситуации с помощью ОО подхода, которое в последующем сильно экономило мое время.
Предыстория
Как то раз возникла задача организовать класс "Хранитель", которые позволяет хранить в себе текущее состояние родительского объекта и восстанавливать его когда это потребуется, при чем раскрывать это состояние позволяется только родительскому объекту, дабы не нарушить инкапсуляции (кто знаком с шаблонами проектирования, мне понадобился обычный Хранитель). Реализовал его за несколько минут и решил пойти дальше: а почему бы не организовать такой Хранитель, который сможет переносить состояния объектов между обращениями к скрипту? Ведь для этого достаточно воспользоваться каким нибудь хранилищем типа сессии или БД. Идея мне очень понравилась (с учетом того, что я несколько месяцев реализую собственную ORM) и я принялся за разработку.
Важные вопросы архитектуры
1. Первым вопросом, который предстояло решить был - придется ли мне переписывать каждый класс Хранитель под отдельное Хранилище? Другими словами стоит ли создать два класса: ХранительСессии и ХранительБД - чтобы каждый тип Хранителя мог переносить состояния в разных Хранилищах? Здесь заметно явное дублирование кода, так как многие методы будут идентичны в этих двух Хранителях, различаются только методы доступа к данным Хранилища.
2. Второй вопрос прямо вытекает из первого - правильно ли использовать алгоритмы доступа к данным сессии, запуск сессии, добавления и удаления в ней данных, через интерфейсы и методы самого Хранителя? Ведь каждый класс должен выполнять строго ограниченные задачи, а любой Хранитель уже выполняет задачу хранения и возврата состояния родителя?!
3. Третий вопрос возник, когда я задумался о вынесении механизмов работы с Хранилищами в отдельный класс - как организовать Хранитель так, чтобы он мог безошибочно найти себя в Хранилище после перезапуска сервиса, т.е. в той ситуации, когда не будет ни родительского объекта, ни самого Хранителя, а останутся только данные в БД или сессии? Хотелось не отходить далеко от принципов ORM и воспользоваться идентификацией по известным атрибутам, на пример, задав объекту его OID или Login и Password, восстановить по ним Хранителя.
Важные решения архитектуры
Возможно, опытные ООПшники уже набросали в голове ответы на все поставленные ранее вопросы, но я распишу все более подробно для остальных (очень жаль, что в статью нельзя встраивать изображения).
1. Для решения первого вопроса мы воспользуемся композицией и делегированием, а так же паттерном Стратегия. Что означают и как применяются эти страшные слова, я объясню чуть позже.
2. Для решения второго вопроса мы используем унифицированный и довольно упрощенный интерфейс работы с Хранилищами. Ведь нам нет необходимости использовать все возможности таких интерфейсов как MySQLi, для решения задач Хранителя достаточно: select, update, remove, input. Причем любое хранилище, будь то сессия, БД или файл может без проблем реализовать эти функции.
3. Не отходя далеко от принципов ORM, я поступил именно так, как сказано в них, а именно использовал известные данные о структуре объекта, для аутентификации его из Хранилища.
Самое интересное
И так реализация и подробное описание всех механизмов. Начну сверху и медленно проберусь в глубь гвнокода.
Что я подразумеваю под Стратегией, композицией и делегированием? Для начала давайте повторим, что такое интерфейс в PHP. Интерфейс это гарантия того, что все классы, его реализующие, будут иметь те методы, что в нем описаны. Интерфейсы так же называют Договором, так как все классы "подписавшиеся" на интерфейс "обязаны" выполнить все его методы ("условия"). Если немного подумать, то любой Хранитель, способный переносить данные между вызовом сервисов, все лишь должен иметь объект, обращающийся к Хранилищам и передавать ему свое состояния для записи и восстановления. Другими словами, зачем вшивать алгоритмы работы с Хранилищами в сам Хранитель, когда можно написать отдельный класс, целью которого будет получение данных и передачу их в Хранилище. Это называется инкапсуляцией методов. Мы выносим метод за пределы класса, и упаковываем его в другой класс. Здесь важно сделать оговорку для слова "упаковываем". Нет! Мы не используем класс как хранилище методов и свойств, это не так. Мы создаем отдельный, полноценный класс, целью которого будет работа с различными Хранилищами. Это очень часто встречающийся подход в ООП. Он позволяет решить еще одну важную задачу - сделать код более гибким. Представьте, что мы реализуем два Хранителя, один хранит данные в Сессии, другой в БД. Для этого одному мы передаем экземпляр класса, работающий с Хранилищем БД, а другому экземпляр класса, работающий с Хранилищем Сессии. Причем тот и другой реализуют упрощенный интерфейс: select, update, remove, input - таким образом, Хранителю не важно, что это за объект и с каким Хранилищем он работает, достаточно знать, что он реализует методы записи и восстановления, которые нужны Хранителю для работы. Такой подход называется композицией - мы передаем объекту другой объект, который будет выполнять некоторые функции за него. Непосредственно использование Хранилища Хранителем называется делегированием задач. Хранитель передает часть работы Хранилищу, делегируя ему некоторые необходимы операции, а Хранилище гарантирует, что эти операции будут выполнены.

Автор статьи: Артур (21.12.11 / 11:21)
Пример ООП, практика ООП, паттерны
Рейтинг: +1
Просмотров: 1773
Комментарии (7) »