вопросы по паттернам

chubbrick

Новичок
только начал изучать паттерны и пока что-то не очень въезжаю в эту тему. Помогите разобраться. Сейчас изучаю по книге Мэтт Зандстра и если сразу непонятно, то копаю статьи в гугле.
Так вот, у меня сложилось такое мнение о паттернах:
1) синглтон - это для бд, настроек и т.д.
2) прототип - это когда начальная генерация объекта занимает время, а в процессе выполнения скрипта надо создавать много таких объектов, поэтому быстрее получается клонировать готовый объект и уже работать с ним.
3) фабрика метод - типа замена new (что-то не очень понял)
4) абстрактная фабрика - вообще не втыкаю
И вообще можно, например, синглтон запихнуть в фабрику? Ну чтобы его генерировать через нее
5)композиция - это когда я хочу складировать одно в другом и в третьем и т.д. и выполнять методы сразу над всеми объектам в этой группе
6)декоратор - для фильтров и кодировщиков и т.д.
7)фасад - типа точки перехода между элементами системы. Обеспечивает их взаимосвязь более простым интерфейсом
8)интерпритатор - ну тут всё ясно
9)стратегия - разделение "всего и побольше". Сочетается с фасадом (можно обеспечивать взаимосвязь компонентов через фасад)
10) наблюдатель - для всяких сообщений (а ля вк), логов и т. д.
Вот как-то так я всё это понял. Объясните пожалуйста где я не прав и про фабрики
 

Фанат

oncle terrible
Команда форума
chubbrick задавая этот вопрос на форуме, ты делаешь большую ошибку.
Здесь нет квалифицированных специалистов, чтобы тебе ответить. Есть только специалисты языком почесать.
 

Redjik

Джедай-мастер
Фанат
День неудачно сложился?
Просто на эти вопросы нереально ответить, ну или книгу писать...
 

fixxxer

К.О.
Партнер клуба
гы :D

Disclaimer: мое понимание паттернов может отличаться от общепринятного, а где-то я могу быть вообще не прав.

Синглтон - паттерн спорный. для настроек, логгера - можно, для соединения с бд - а что будешь делать если понадобится второе?
Если все завернуть в синглтоны, получается ничем не лучше, чем глобальная переменная, просто выглядит ООПшнее.
Почитай статью про управление зависимостями, хотя IoC они там зря хоронят :)

Про прототип в первый раз от тебя услышал, погуглил. Не думаю, что это требуется в php, мне кажется, ту же проблему решает late static binding и статический конструктор, возвращающий и конфигурирующий $instance = new static, хотя, возможно, я не понял суть паттерна.

Абстрактная фабрика в классическом виде switch - case - return new в php нафиг не нужна. Предположим у нас есть классы, представляющие элементы формы - input, select итд и мы хотим по строке с именем элемента создавать инстанс класса с именем FormFieid_Input итд - можно сделать такую фабрику

PHP:
class FormFieldFactory {
    public static function getInstanceByName($element_name) {
        $class_name = 'FormField_' . ucfirst($element_name);
        if (!class_exists($class_name)) {
            throw new LogicException("Unknown element name: '$element_name'");
        }
        return new $class_name;
    }
}
Чтобы не плодить ради этого класс, в таком простом случае, - обычно все равно есть абстрактный базовый класс FormField - вот туда его и засунем, это получится factory method. С другой стороны, если логика более сложная, уместно ее вынести как раз в отдельный класс.

"синглтон запихнуть в фабрику" - в смысле саму фабрику сделать синглтоном? - ну обычно достаточно просто статики, хотя если нужна конфигурация фабрики, то да. Если в смысле сделать один класс, управляющий пачкой синглтонов - да, можно, получится смесь Registry с фабрикой - у этой идеи есть множество вариантов реализации, опять же отсылаю к статье об управлении зависимостями.

Композиция - все верно понял

Декторатор - на примере php скорее будет такая реализация: ты хочешь добавить поведение, но не хочешь или не можешь наследоваться (например, уже наследуешься от чего-то другого), тогда ты держишь protected $Base ссылку на "расширяемый" объект, и прокидываешь вызовы как-то так
PHP:
public function __call($method, $args) {
    if (!method_exists($this->Base, $method)) {
        throw new BadMethodCallException("Unknown method: '$method'");
    }
    return call_user_func_array(array($this->base, $method), $args);
}
Фасад это когда у тебя есть куча классов с их зависимостями, которые надо всяко настроить, но ты хочешь, чтобы пользователи твоей библиотеки всем этим не заморачивались а просто дергали методы одного единственного класса.

Стратегия это выбор одной из реализаций в зависимости от условий. Примерно как в PDO - есть общий интерфейс и есть конкретные драйверы mysql, pgsql итд.

Observer - это ООП-реализация того, для чего говнокодеры пишут хуки. :) проще объяснить по аналогичному паттерну publisher-subscriber - тут явно видно две роли. При выполнении какого-то действия все подписчики о нем оповещаются (путем вызова соответствующего метода). В википедии неплохой пример.
 

Redjik

Джедай-мастер
Добавлю observer отлично реализован в yii. (events)
Чаще всего он нужен для изменения стандартного workflow приложения (я говорю про php реализацию - в книжках по Java немного другое назначение описывают).
 

Фанат

oncle terrible
Команда форума
а что будешь делать если понадобится второе?
Вот кстати, мне ужа давно пришла в голову такая идея:
для нового соединения наследовать класс. и обращаться, соответственно
PHP:
db::query(...);
tdb::query(...);
получается и красиво, и синглтон
 

Вурдалак

Продвинутый новичок
Фанат, надо отдыхать чаще. Инстанс всё равно один будет, static же. Да и использование наследования не по назначению называть чем-то красивым — ужас. Если уж на то пошло, можно сделать db::getLink('db1'), db::getLink('db2').
 

cDLEON

Онанист РНРСlub
А потом вам вдруг понадобится один из модулей перенести на первую БД и вы будете сидеть и делать find and replace по всем файлам, которые этой БД должны касаться.
Синглтон это антипаттерн в PHP. Я не могу даже придумать себе где его можно использовать.
 

fixxxer

К.О.
Партнер клуба
Вот кстати, мне ужа давно пришла в голову такая идея:
для нового соединения наследовать класс. и обращаться, соответственно
PHP:
db::query(...);
tdb::query(...);
получается и красиво, и синглтон
ой, это ж все внутрях статиками делать...

тогда уж лучше __callStatic + ConnectionManager::db()->query(...), заодно будет этакой фабрикой, внутрях этакий скрытый синглтон этого самого менеджера. я по такому принципу registry делал.
 

Crys

Двинутый новичок
о, что-то я не проассоциировал :)
ну а применительно к class-based ООП это как?
Обычное клонирование. В js нет классов, поэтому аналог наследования классов и делается прототипами. В php используется как chubbrick и описал.. когда изначальная инициализация ресурсоемкая - клонируем объект, если надо - вносим в него изменения.
 

Фанат

oncle terrible
Команда форума
ой, это ж все внутрях статиками делать...
именно!
получится коротко, красиво и юзабельно!
инстанс класса для работы с БД нафиг не нужен.

Равно как и ConnectionManager.
мне не нужна суперкрасивая ООП-структура, одно обращение к которой занимает пол-строки. Мне нужен удобный и короткий способ обращаться к БД.

Рассуждаю я так. По уму для работы с БД достаточно статик методов.
следовательно, инстанс класса нам нафиг не нужен. Но мешает нам именно синглтонность и РЕДКАЯ необходимость иметь два инстанса. И наследование, имхо, эту задачу красиво решает!

но если у тебя есть аргументированные возражения - я с радостью приму в дар.
 

fixxxer

К.О.
Партнер клуба
У меня, на самом деле, менеджер соединений сделан из других соображений. :)
Мне бывает нужно синхронно управлять транзакциями во всех соединениях.
Т.е. пишу ConnectionManager::begin(), и стартуем транзакцию везде, где она еще не стартована, итд.
 

Фанат

oncle terrible
Команда форума
[Инстанс всё равно один будет, static же.
не понял. почему один и тот же? db - это инстанс класса db, а tdb - инстанс класса tdb
db тоже наследуется от базового класса при инициализации.

у хорошо, я делаю неправильно. а как праивльно? Создавать инстанс и везде, где нужна база, писать global $db?
 

cDLEON

Онанист РНРСlub
На самом деле
у хорошо, я делаю неправильно. а как праивльно? Создавать инстанс и везде, где нужна база, писать global $db?
У тебя ни чем не отличается от tbh::query. Только global $blabla здесь не явно используется.
По-хорошему, имхо, это будет геттер в контроллере. Да ещё и с инициализацией по требованию. А уже откуда его будет брать контроллер, ты решаешь сам. У меня такие вещи инжектируется в контроллер через конструктор.
 

Фанат

oncle terrible
Команда форума
ну да. от этого дурацкого глобала я и хочу уйти.
меня бесит бессмысленный повторяемый код.
мне кажется, статические методы как раз и придуманы для этого
что плохого в статическом синглтоне для работы с БД?
 

Redjik

Джедай-мастер
Обычное клонирование. В js нет классов, поэтому аналог наследования классов и делается прототипами. В php используется как chubbrick и описал.. когда изначальная инициализация ресурсоемкая - клонируем объект, если надо - вносим в него изменения.
В теории да, только в жизни ни разу не встречал такого...
Для меня просто еще одна галочка - о я знаю этот пэттерн =)
 
Сверху