1. Для манипуляции любой сущностью реализуется интерфейс, скрывающий максимально возможное количество деталей используемой сущности.
2. Между сущностью, которой мы манипулируем, и клиентским кодом должна быть прослойка, реализующая алгоритмы работы с это сущностью и не привязанная к деталям реализации кода созданного в п.1.
Пользуясь терминологией STL'я у нас есть контейнер (п.1), оборачивающий какую-либо сущность и есть алгоритмы (п.2), которым пофиг и на контейнер и на саму сущность. Примерно то же предлагается делать и для своего кода.
На практике осуществить это достаточно просто. Сначала расписываем все методы, необходимые для работы с сущностью. Потом начинаем по одному перебирать все эти методы, отвечая каждый раз на одни и те же вопросы: этот метод знает что-либо об обрабатываемой сущности? Можно ли реализовать эту функцию, так чтобы она ничего не знала об обрабатываемой сущности? Ну и в зависимости от ответов помещаем функцию либо в кучку с алгоритмами, либо в кучку с контейнерами.
Для самоконтроля предлагаю следующий критерий:
Критерий неправильно проведенного разбиения: если алгоритмы используют типы данных введенные обрабатываемой сущностью, то разбиение проведено неверно.
Следствие из критерия: методы контейнера в качестве типов параметров должны использовать либо стандартные типы (в том числе и STL'ные), либо типы данных, введенные в клиентском коде.
При проведении разбиения может возникнуть ситуация, когда алгоритм рациональнее сделать частью контейнера (например, когда мы получим существенный выигрыш в скорости от такого переноса). Пример: есть хранилище учеток пользователей, которое может быть реализовано либо через БД (для больших сайтов, с большим количеством пользователей) либо через файловую систему (для маленьких сайтов с небольшим количеством пользователей), когда каждая учетка хранится в отдельном файле. У нас есть функция получения списка всех пользователей, и нам нужно сделать функцию, получения количества учеток. В этом примере сущностью является хранилище учеток. Во втором случае самый простой способ вернуть count( $Accounts ), записей-то немного. А вот в первом случае, когда число записей легко переходит за 1000 этот способ будет накладен в плане производительности и будет лучше сделать SELECT COUNT( * ) FROM ... В первом случае у нас метод контейнера, а во втором алгоритм. Поэтому в этом примере рациональнее принять решение о том чтобы сделать алгоритм частью интерфейса контейнера. На практике таких случаев встречается не очень много, однако их все равно стоит избегать, т.к. основное назначение описываемого паттерна облегчить смену хранимых сущностей, а чем больше будет интерфейс контейнера тем сложнее это будет сделать.
PS Ссылки по теме:
Open source убьёт мир
Фокусы с наследованием
Стандарты кодирования
Старые парадигмы о главном