Паттерн что это значит

Основы паттернов проектирования

Что представляют собой паттерны проектирования? Паттерн представляет определенный способ построения программного кода для решения часто встречающихся проблем проектирования. В данном случае предполагается, что есть некоторый набор общих формализованных проблем, которые довольно часто встречаются, и паттерны предоставляют ряд принципов для решения этих проблем.

Хотя идея паттернов как способ описания решения распространенных проблем в области проектирования появилась довольно давно, но их популярность стала расти во многом благодаря известной работе четырех авторов Эриха Гаммы, Ричарда Хелма, Ральфа Джонсона, Джона Влиссидеса, которая называлась «Design Patterns: Elements of Reusable Object-Oriented Software» (на русском языке известна как «Приемы объектно-ориентированного проектирования. Паттерны проектирования») и которая вышла в свет в 1994 году. А сам коллектив авторов нередко называют «Банда четырёх» или Gang of Four или сокращенно GoF. Данная книга по сути являлась первой масштабной попыткой описать распространенные способы проектирования программ. И со временем применение паттернов стало считаться хорошей практикой программирования.

Паттерны это что? Паттерн в психологии что это такое — Рубрика «ЭТО ЧТО»

Что же дает нам применение паттернов? При написании программ мы можем формализовать проблему в виде классов и объектов и связей между ними. И применить один из существующих паттернов для ее решения. В итоге нам не надо ничего придумывать. У нас уже есть готовый шаблон, и нам только надо его применить в конкретной программе.

Причем паттерны, как правило, не зависят от языка программирования. Их принципы применения будут аналогичны и в C#, и в Jave, и в других языках. Хотя в рамках данного руководства мы будем говорить о паттернах в контексте языка C#.

Также мышление паттернами упрощает групповую разработку программ. Зная применяемый паттерн проектирования и его основные принципы другому программисту будет проще понять его реализацию и использовать ее.

В то же время не стоит применять паттерны ради самих паттернов. Хорошая программа предполагает использование паттернов. Однако не всегда паттерны упрощают и улучшают программу. Неоправданное их использование может привести к усложнению программного кода, уменьшению его качества. Паттерн должен быть оправданным и эффективным способом решения проблемы.

Существует множество различных паттернов, которые решают разные проблемы и выполняют различные задачи. Но по своему действию их можно объединить в ряд групп. Рассмотрим некоторые группы паттернов. В основу классификации основных паттернов положена цель или задачи, которые определенный паттерн выполняет.

Порождающие паттерны

Порождающие паттерны — это паттерны, которые абстрагируют процесс инстанцирования или, иными словами, процесс порождения классов и объектов. Среди них выделяются следующие:

  • Абстрактная фабрика (Abstract Factory)
  • Строитель (Builder)
  • Фабричный метод (Factory Method)
  • Прототип (Prototype)
  • Одиночка (Singleton)

Другая группа паттернов — структурные паттерны — рассматривает, как классы и объекты образуют более крупные структуры — более сложные по характеру классы и объекты. К таким шаблонам относятся:

ПАТТЕРН поведения — что это? Психология простыми словами

  • Адаптер (Adapter)
  • Мост (Bridge)
  • Компоновщик (Composite)
  • Декоратор (Decorator)
  • Фасад (Facade)
  • Приспособленец (Flyweight)
  • Заместитель (Proxy)

Третья группа паттернов называются поведенческими — они определяют алгоритмы и взаимодействие между классами и объектами, то есть их поведение. Среди подобных шаблонов можно выделить следующие:

  • Цепочка обязанностей (Chain of responsibility)
  • Команда (Command)
  • Интерпретатор (Interpreter)
  • Итератор (Iterator)
  • Посредник (Mediator)
  • Хранитель (Memento)
  • Наблюдатель (Observer)
  • Состояние (State)
  • Стратегия (Strategy)
  • Шаблонный метод (Template method)
  • Посетитель (Visitor)

Существуют и другие классификации паттернов в зависимости от того, относится паттерн к классам или объектам.

Паттерны классов описывают отношения между классами посредством наследования. Отношения между классами определяются на стадии компиляции. К таким паттернам относятся:

  • Фабричный метод (Factory Method)
  • Интерпретатор (Interpreter)
  • Шаблонный метод (Template Method)
  • Адаптер (Adapter)

Другая часть паттернов — паттерны объектов описывают отношения между объектами. Эти отношения возникают на этапе выполнения, поэтому обладают большей гибкостью. К паттернам объектов относят следующие:

  • Абстрактная фабрика (Abstract Factory)
  • Строитель (Builder)
  • Прототип (Prototype)
  • Одиночка (Singleton)
  • Мост (Bridge)
  • Компоновщик (Composite)
  • Декоратор (Decorator)
  • Фасад (Facade)
  • Приспособленец (Flyweight)
  • Заместитель (Proxy)
  • Цепочка обязанностей (Chain of responsibility)
  • Команда (Command)
  • Итератор (Iterator)
  • Посредник (Mediator)
  • Хранитель (Memento)
  • Наблюдатель (Observer)
  • Состояние (State)
  • Стратегия (Strategy)
  • Посетитель (Visitor)

И это только некоторые основные паттерны. А вообще различных шаблонов проектирования гораздо больше. Одни из них только начинают применяться, другие являются популярными на текущий момент, а некоторые уже менее распространены, чем раньше.

И в данном руководстве мы рассмотрим наиболее основные и распространенные паттерны и принципы их использования применительно к языку C#.

Как выбрать нужный паттерн?

Прежде всего при решении какой-нибудь проблемы надо выделить все используемые сущности и связи между ними и абстрагировать их от конкретной ситуации. Затем надо посмотреть, вписывается ли абстрактная форма решения задачи в определенный паттерн. Например, суть решаемой задачи может состоять в создании новых объектов. В этом случае, возможно, стоит посмотреть на порождающие паттерны. Причем лучше не сразу взять какой-то определенный паттерн — первый, который показался нужным, а посмотреть на несколько родственных паттернов из одной группы, которые решают одну и ту же задачу.

При этом важно понимать смысл и назначение паттерна, явно представлять его абстрактную организацию и его возможные конкретные реализации. Один паттерн может иметь различные реализации, и чем чаще вы будете сталкиваться с этими реализациями, тем лучше вы будете понимать смысл паттерна. Но не стоит использовать паттерн, если вы его не понимаете, даже если он на первый взгляд поможет вам в решении задачи.

И в конечном счете надо придерживаться принципа KISS (Keep It Simple, Stupid) — сохранять код программы по возможности простым и ясным. Ведь смысл паттернов не в усложнении кода программы, а наоборот в его упрощении.

Источник: metanit.com

Шаблоны проектирования простым языком. Часть первая. Порождающие шаблоны

Первая статья из цикла, посвящённого шаблонам, или паттернам, проектирования. На понятных примерах объясняем суть порождающих шаблонов.

Обложка поста design-patterns-simple-words-1

Рассказывает Камран Ахмед

На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.

Шаблоны проектирования — это руководства по решению повторяющихся проблем. Это не классы, пакеты или библиотеки, которые можно было бы подключить к вашему приложению и сидеть в ожидании чуда. Они скорее являются методиками, как решать определенные проблемы в определенных ситуациях.

Википедия описывает их следующим образом:

Будьте осторожны

  • шаблоны проектирования не являются решением всех ваших проблем;
  • не пытайтесь использовать их в обязательном порядке — это может привести к негативным последствиям. Шаблоны — это подходы к решению проблем, а не решения для поиска проблем;
  • если их правильно использовать в нужных местах, то они могут стать спасением, а иначе могут привести к ужасному беспорядку.

Также заметьте, что примеры ниже написаны на PHP 7. Но это не должно вас останавливать, ведь принципы остаются такими же.

Типы шаблонов

Шаблоны бывают следующих трех видов:

Если говорить простыми словами, то это шаблоны, которые предназначены для создания экземпляра объекта или группы связанных объектов.

Существуют следующие порождающие шаблоны:

  • простая фабрика (Simple Factory);
  • фабричный метод (Factory Method);
  • абстрактная фабрика (Abstract Factory);
  • строитель (Builder);
  • прототип (Prototype);
  • одиночка (Singleton).

Простая фабрика (Simple Factory)

Пример из жизни: Представьте, что вам надо построить дом, и вам нужны двери. Было бы глупо каждый раз, когда вам нужны двери, надевать вашу столярную форму и начинать делать дверь. Вместо этого вы делаете её на фабрике.

Простыми словами: Простая фабрика генерирует экземпляр для клиента, не раскрывая никакой логики.

Перейдем к коду. У нас есть интерфейс Door и его реализация:

interface Door < public function getWidth(): float; public function getHeight(): float; >class WoodenDoor implements Door < protected $width; protected $height; public function __construct(float $width, float $height) < $this->width = $width; $this->height = $height; > public function getWidth(): float < return $this->width; > public function getHeight(): float < return $this->height; > >

Затем у нас есть наша DoorFactory , которая делает дверь и возвращает её:

class DoorFactory < public static function makeDoor($width, $height): Door < return new WoodenDoor($width, $height); >>

И затем мы можем использовать всё это:

$door = DoorFactory::makeDoor(100, 200); echo ‘Width: ‘ . $door->getWidth(); echo ‘Height: ‘ . $door->getHeight();

Когда использовать: Когда создание объекта — это не просто несколько присвоений, а какая-то логика, тогда имеет смысл создать отдельную фабрику вместо повторения одного и того же кода повсюду.

Фабричный метод (Fabric Method)

Пример из жизни: Рассмотрим пример с менеджером по найму. Невозможно одному человеку провести собеседования со всеми кандидатами на все вакансии. В зависимости от вакансии он должен распределить этапы собеседования между разными людьми.

Простыми словами: Менеджер предоставляет способ делегирования логики создания экземпляра дочерним классам.

Перейдём к коду. Рассмотрим приведенный выше пример про HR-менеджера. Изначально у нас есть интерфейс Interviewer и несколько реализаций для него:

interface Interviewer < public function askQuestions(); >class Developer implements Interviewer < public function askQuestions() < echo ‘Спрашивает про шаблоны проектирования!’; >> class CommunityExecutive implements Interviewer < public function askQuestions() < echo ‘Спрашивает о работе с сообществом’; >>

Теперь создадим нашего HiringManager :

abstract class HiringManager < // Фабричный метод abstract public function makeInterviewer(): Interviewer; public function takeInterview() < $interviewer = $this->makeInterviewer(); $interviewer->askQuestions(); > >

И теперь любой дочерний класс может расширять его и предоставлять необходимого интервьюера:

class DevelopmentManager extends HiringManager < public function makeInterviewer(): Interviewer < return new Developer(); >> class MarketingManager extends HiringManager < public function makeInterviewer(): Interviewer < return new CommunityExecutive(); >>
$devManager = new DevelopmentManager(); $devManager->takeInterview(); // Вывод: Спрашивает о шаблонах проектирования! $marketingManager = new MarketingManager(); $marketingManager->takeInterview(); // Вывод: Спрашивает о работе с сообществом

Когда использовать: Полезен, когда есть некоторая общая обработка в классе, но необходимый подкласс динамически определяется во время выполнения. Иными словами, когда клиент не знает, какой именно подкласс ему может понадобиться.

Примеры на Java и Python.

Абстрактная фабрика (Abstract Factory)

Пример из жизни: Расширим наш пример про двери из простой фабрики. В зависимости от ваших нужд вам понадобится деревянная дверь из одного магазина, железная дверь — из другого или пластиковая — из третьего. Кроме того, вам понадобится соответствующий специалист: столяр для деревянной двери, сварщик для железной двери и так далее. Как вы можете заметить, тут есть зависимость между дверьми.

Простыми словами: Фабрика фабрик. Фабрика, которая группирует индивидуальные, но связанные/зависимые фабрики без указания их конкретных классов.

Обратимся к коду. Используем пример про двери. Сначала у нас есть интерфейс Door и несколько его реализаций:

interface Door < public function getDescription(); >class WoodenDoor implements Door < public function getDescription() < echo ‘Я деревянная дверь’; >> class IronDoor implements Door < public function getDescription() < echo ‘Я железная дверь’; >>

Затем у нас есть несколько DoorFittingExpert для каждого типа дверей:

interface DoorFittingExpert < public function getDescription(); >class Welder implements DoorFittingExpert < public function getDescription() < echo ‘Я работаю только с железными дверьми’; >> class Carpenter implements DoorFittingExpert < public function getDescription() < echo ‘Я работаю только с деревянными дверьми’; >>

Теперь у нас есть DoorFactory , которая позволит нам создать семейство связанных объектов. То есть фабрика деревянных дверей предоставит нам деревянную дверь и эксперта по деревянным дверям. Аналогично для железных дверей:

interface DoorFactory < public function makeDoor(): Door; public function makeFittingExpert(): DoorFittingExpert; >// Деревянная фабрика вернет деревянную дверь и столяра class WoodenDoorFactory implements DoorFactory < public function makeDoor(): Door < return new WoodenDoor(); >public function makeFittingExpert(): DoorFittingExpert < return new Carpenter(); >> // Железная фабрика вернет железную дверь и сварщика class IronDoorFactory implements DoorFactory < public function makeDoor(): Door < return new IronDoor(); >public function makeFittingExpert(): DoorFittingExpert < return new Welder(); >>
$woodenFactory = new WoodenDoorFactory(); $door = $woodenFactory->makeDoor(); $expert = $woodenFactory->makeFittingExpert(); $door->getDescription(); // Вывод: Я деревянная дверь $expert->getDescription(); // Вывод: Я работаю только с деревянными дверями // Аналогично для железной двери $ironFactory = new IronDoorFactory(); $door = $ironFactory->makeDoor(); $expert = $ironFactory->makeFittingExpert(); $door->getDescription(); // Вывод: Я железная дверь $expert->getDescription(); // Вывод: Я работаю только с железными дверями

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

Когда использовать: Когда есть взаимосвязанные зависимости с не очень простой логикой создания.

Примеры на Java и Python.

Строитель (Builder)

Пример из жизни: Представьте, что вы пришли в McDonalds и заказали конкретный продукт, например, БигМак, и вам готовят его без лишних вопросов. Это пример простой фабрики. Но есть случаи, когда логика создания может включать в себя больше шагов. Например, вы хотите индивидуальный сэндвич в Subway: у вас есть несколько вариантов того, как он будет сделан. Какой хлеб вы хотите?

Какие соусы использовать? Какой сыр? В таких случаях на помощь приходит шаблон «Строитель».

Простыми словами: Шаблон позволяет вам создавать различные виды объекта, избегая засорения конструктора. Он полезен, когда может быть несколько видов объекта или когда необходимо множество шагов, связанных с его созданием.

Давайте я покажу на примере, что такое «Телескопический конструктор». Когда-то мы все видели конструктор вроде такого:

public function __construct($size, $cheese = true, $pepperoni = true, $tomato = false, $lettuce = true)

Как вы можете заметить, количество параметров конструктора может резко увеличиться, и станет сложно понимать расположение параметров. Кроме того, этот список параметров будет продолжать расти, если вы захотите добавить новые варианты. Это и есть «Телескопический конструктор».

Перейдем к примеру в коде. Адекватной альтернативой будет использование шаблона «Строитель». Сначала у нас есть Burger , который мы хотим создать:

class Burger < protected $size; protected $cheese = false; protected $pepperoni = false; protected $lettuce = false; protected $tomato = false; public function __construct(BurgerBuilder $builder) < $this->size = $builder->size; $this->cheese = $builder->cheese; $this->pepperoni = $builder->pepperoni; $this->lettuce = $builder->lettuce; $this->tomato = $builder->tomato; > >

Затем мы берём «Строителя»:

class BurgerBuilder < public $size; public $cheese = false; public $pepperoni = false; public $lettuce = false; public $tomato = false; public function __construct(int $size) < $this->size = $size; > public function addPepperoni() < $this->pepperoni = true; return $this; > public function addLettuce() < $this->lettuce = true; return $this; > public function addCheese() < $this->cheese = true; return $this; > public function addTomato() < $this->tomato = true; return $this; > public function build(): Burger < return new Burger($this); >>
$burger = (new BurgerBuilder(14)) ->addPepperoni() ->addLettuce() ->addTomato() ->build();

Когда использовать: Когда может быть несколько видов объекта и надо избежать «телескопического конструктора». Главное отличие от «фабрики» — это то, что она используется, когда создание занимает один шаг, а «строитель» применяется при множестве шагов.

Примеры на Java и Python.

Прототип (Prototype)

Пример из жизни: Помните Долли? Овечка, которая была клонирована. Не будем углубляться, главное — это то, что здесь все вращается вокруг клонирования.

Простыми словами: Прототип создает объект, основанный на существующем объекте при помощи клонирования.

То есть он позволяет вам создавать копию существующего объекта и модернизировать его согласно вашим нуждам, вместо того, чтобы создавать объект заново.

Обратимся к коду. В PHP это может быть легко реализовано с использованием clone :

class Sheep < protected $name; protected $category; public function __construct(string $name, string $category = ‘Горная овечка’) < $this->name = $name; $this->category = $category; > public function setName(string $name) < $this->name = $name; > public function getName() < return $this->name; > public function setCategory(string $category) < $this->category = $category; > public function getCategory() < return $this->category; > >

Затем он может быть клонирован следующим образом:

$original = new Sheep(‘Джолли’); echo $original->getName(); // Джолли echo $original->getCategory(); // Горная овечка // Клонируем и модифицируем то что нужно $cloned = clone $original; $cloned->setName(‘Долли’); echo $cloned->getName(); // Долли echo $cloned->getCategory(); // Горная овечка

Также вы можете использовать волшебный метод __clone для изменения клонирующего поведения.

Когда использовать: Когда необходим объект, похожий на существующий объект, либо когда создание будет дороже клонирования.

Примеры на Java и Python.

Одиночка (Singleton)

Пример из жизни: В стране одновременно может быть только один президент. Один и тот же президент должен действовать, когда того требуют обстоятельства. Президент здесь является одиночкой.

Простыми словами: Обеспечивает тот факт, что создаваемый объект является единственным объектом своего класса.

Вообще шаблон одиночка признан антипаттерном, необходимо избегать его чрезмерного использования. Он необязательно плох и может иметь полезные применения, но использовать его надо с осторожностью, потому что он вводит глобальное состояние в ваше приложение и его изменение в одном месте может повлиять на другие части приложения, что вызовет трудности при отладке. Другой минус — это то, что он делает ваш код связанным.

На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.

Подробнее о подводных камнях шаблона одиночка читайте в нашей статье.

Перейдем к коду. Чтобы создать одиночку, сделайте конструктор приватным, отключите клонирование и расширение и создайте статическую переменную для хранения экземпляра:

final class President < private static $instance; private function __construct() < // Прячем конструктор >public static function getInstance(): President < if (!self::$instance) < self::$instance = new self(); >return self::$instance; > private function __clone() < // Отключаем клонирование >private function __wakeup() < // Отключаем десериализацию >>
$president1 = President::getInstance(); $president2 = President::getInstance(); var_dump($president1 === $president2); // true

Источник: tproger.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
Заработок в интернете или как начать работать дома