![]() |
Паттерны проектирования Уважаемые разработчики. Как вы применяете в своих проектах шаблоны легендарной банды четырех (декоратор, адаптер, шаблонный метод и т.д.)? Есть ли в Краснодаре программисты (или команды), умеющие общаться на бронебойном языке паттернов? Возможны ли тематические встречи для обмена опытом? |
Паттерн Абстрактная фабрика [url]http://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%B0%D1%8F_%D1%84%D0%B0%D0%B1%D1%80%D0%B8%D0%BA%D0%B0_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F[/url]) Начнем обсуждение с рассмотрения простого примера. Допустим есть некий веб-система документооборота и в нем мы реализуем 2 разных интерфейса для управления различными типами пользователей (физ и юр лица, коротко юрик и физик). У каждого типа пользователя есть общие и уникальные атрибуты (сначала идут общие). Физик: ID, телефон, email,ФИО, номер паспорта, ОГРНИП Юрик: ID, телефон, email, название организации, ОГРН Допустим этот набор полей хранится в базе и он всегда нам доступен через операцию $db::get_fields($type) где $type = 0 юрик, 1 физик. В каждом веб-интерфейсе должен быть фильтр и таблица. Операции фильтрации, сортировки, создания, редактирования, удаления полностью идентичны для обоих типов. Вот здесь и применяется шаблон абстрактная фабрика. Схематично я изобразил его так: [img]http://web112.biz/files/abstract_factory.jpg[/img] А теперь код: <?php interface UserFactory ** public function get_filter_data(); public function get_table_data(); ** class LegalFactory implements UserFactory ** public function get_filter_data() ** return (new LegalFilter()); ** public function get_table_data() ** return (new LegalTable()); ** ** class NaturalFactory implements UserFactory ** public function get_filter_data() ** return (new NaturalFilter()); ** public function get_table_data() ** return (new NaturalTable()); ** ** abstract class UserFilter ** // возвращает данные, которые уже дльше передаем в представление filter.tpl public function get_data(); ** class LegalFilter extends UserFilter ** ** class NaturalFilter extends UserFilter ** ** abstract class UserTable ** // возвращает данные, которые уже дльше передаем в представление table.tpl public function get_data(); ** class LegalTable extends UserTable ** ** class NaturalTable extends UserTable ** ** class Client ** private $factory; public function legal_builder() ** $this->factory = new LegalFactory(); ** public function natural_builder() ** $this->factory = new NaturalFactory(); ** public function out() ** echo $this->factory->get_filter_data(); echo $this->factory->get_table_data(); ** ** $client = new Client(); $client->legal_builder(); $client->out(); |
В коде забыл дописать использование $db::get_fields($type) но я думаю, вы и сами без проблем допишите |
Чего мы добились? Мы инкапсулировали наиболее часто изменяемую логику: изменение типов лиц (например, добавление 3-го ИП), изменение полей для каждого тип. При этом код клиента остается неизменным очень долгое время. У этого паттерна есть родственный - фабричный метод. Он отличается тем, что за создание объекта отвечает абстрактный родительский метод, который переопределяется в подклассах. |
Код плохо вставился. Вместо ** должно быть ** |
т.е. открывающая фигурная скобка |
Ничего, мы привыкли к людям, которые кроме классов и MVC ничего не знают. |
В далеком 2005-м году видел проект, нашпигованный паттернами по самое нехочу. Работал крайне медленно. Поддерживать его было вообще мрак. Правда, это был еще .NET 1.1, но с тех пор отношение к паттернам у меня осторожное. |
Это что такое было? :) |
7-CPU > Чтобы паттерны не превратились в плохое решение, не нужно слепо следовать им. Еще есть рефакторинг и код ревью. |
0-КоРоЛь > Весьма активно использую. Наиболее полезен "Шаблонный метод", на втором месте "Фасад", тройку лидеров замыкает Синглтон. |
Паттерн Стратегия. [url]http://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D0%B0%D1%82%D0%B5%D0%B3%D0%B8%D1%8F_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F[/url]) Разрабатываем веб-систему, состоящую из набора интерфейсов. Каждый интерфейс состоит из фильтра и таблицы. Поля в фильтре задаются программно. Т.е. какие поля будут выводиться в конкретном фильтре — мы заранее не знаем. У нас есть следующие типы полей: текст (имеется ввиду текстовое поле ввода) селект чекбокс (имеется ввиду один квадратик) радиокнопки (имеется ввиду несколько кружочков) Чтобы вывести поле, нам нужно знать данные: name — имя латинскими буквами, используется для идентификации поля в форме (атрибут name у инпута) caption — русскоязычное название value — текущее значение value_list — список предопределенных значений поля. Эти данные нужны только для селекта и радиокнопки Простой метод решения — сделать общего предка Field и все операции запихнуть в него - изображен на следующей схеме: [img]http://web112.biz/files/patterns/bad_primer_for_strategy.jpg[/img] Получается, что у текста и чекбокса тоже может быть список значений — но это неправильно. Правильное решение. Выделить типы поведения полей. В данном случае у нас может быть 2 поведения: TextBehavior и SelectBehavior. При этом класс field будет делегировать процедуру получения значений другому объекту. Как это будет выглядеть: [img]http://web112.biz/files/patterns/strategy.jpg[/img] Получается, что при создании поля клиент должен установить поведение этому полю. В классе SelectBehavior мы расписываем процедуру получения списка значений. В классе TextBehavior мы оставляем пустую реализацию метода get_value_list Теперь сам код: <?php // общий класс class Field ** protected $name; protected $caption; protected $value; protected $behavior; public function __construct(Behavior $behavior) ** $this->set_behavior($behavior); ** public function set_behavior($behavior) ** $this->behavior = $behavior; ** public function get_value_list() ** return $this->behavior->get_value_list(); ** ** class Text extends Field ** // тут пишем специфичный код для поля ** class Select extends Field ** // тут пишем специфичный код для поля ** class Checkbox extends Field ** // тут пишем специфичный код для поля ** class Radio extends Field ** // тут пишем специфичный код для поля ** interface Behavior ** public function get_value_list(); ** class SelectBehavior ** public function get_value_list() ** // берем список значений из базы $value_list = array('a', 'b', 'c'); return $value_list; ** ** class TextBehavior ** public function get_value_list() ** ** ** /** * Код клиента теперь можно писать таким образом */ $text_behavior = new TextBehavior(); $select_behavior = new SelectBehavior(); $text = new Text($text_behavior); $checkbox = new Checkbox($text_behavior); $select = new Select($select_behavior); $radio = new Radio($select_behavior); /** * дальше идет вывод полей например так echo $text->display(); * или передача шаблонизатору */ |
Стратегия - уникальный паттерн, который можно использовать где угодно. Задача этого паттерна - инкапсулировать сложные алгоритмы. Еще стратегия является частью реализации паттерна MVC. Если представления представить как общий класс представления и представление каждого интерфейса. Поведение представления инкапсулируется в контроллерах, которые так же разбиваются на общий класс контроллера и контроллер для каждого интерфейса. Так же, этот паттерн показывает наглядные преимущества композиции перед наследованием. |
10-Философ > Синглтон в вебе должен быть на первом месте ) В каких контекстах (предметных областях) обычно используете фасад? |
Еще стратегия незаменимый паттерн в программировании игрушек. Когда разных персонажей могут быть разные виды оружия. |
11-КоРоЛь > прекращай такие простыни постить. 13-КоРоЛь > фасад - по прямому назначению (например, веб-сервис объединяет тучу мелких компонентов в одну подсистему) >Синглтон в вебе должен быть на первом месте ) до самого веба я так и не добрался (пока не добрался) |
Из разговора двух программистов, использующих паттерны: - Буду делать древовидную структуру объектов с помощью компоновщика, обходить ее можно будет визиторами без особых потерь быстродействия. - А я сделаю фасад, чтобы предоставить интерфейс для управления твоими объектами. - Постой, но у нас в коде есть старые объекты, которые нельзя будет изменить под новую структуру. - Точно.. тогда для них мы будем использовать декораторы. - Согласен, это будет идеальное решение! |
[quote=Философ;26833995] 11-КоРоЛь > прекращай такие простыни постить. [/quote] Что не так и почему на ты? |
16-КоРоЛь > Если коту делать нечего, он яйца лижет. Программисту делать нечего - ищет куда-бы ещё прилепить паттерн. Если ничего хорошего придумать не удалось, по умолчанию используется Визитор - поубивал бы! |
18-Философ > прошу использовать свои высказывания в чуть более вежливой форме, ок? Или если это крик души, не направляйте его в мою сторону. Если грамотно использовать визитор, это очень мощный паттерн. Через него можно создавать/удалять/сортировать/перемещать/находить ветки/листья дерева. По большому все эти алгоритмы можно использовать в самом компоновщике, но если используются неоднородные типы узлов в дереве, получается дублирование, которое визитор успешно убирает. Правда его серьезный минус в том, что он "знает" код компоновщика. Про визитор есть любопытная статья на хабре (про upcast visitor можно не читать) [url]http://habrahabr.ru/post/133183/[/url] |
19-КоРоЛь > отвратительная статья! Аффтар с самого начала демонстрирует незнание методик OOD: без выделения семантики объектов сразу начинает с диаграммы классов. Есстественно, что с самых первых строк нарушение SRP... в мусор! |
слабовато как-то.. |
Текущее время: 09:57. Часовой пояс GMT +3. |