Patterns Flashcards
Виды шаблонов
1, Порождающие.
- Структурные.
- Поведенческие.
Порождающие шаблоны
абстрагируют процесс инстанцирования. Они позволяют сделать систему независимой от способа создания, композиции и представления объектов. Шаблон, порождающий классы, использует наследование, чтобы изменять наследуемый класс, а шаблон, порождающий объекты, делегирует инстанцирование другому объекту.
Список порождающих шаблонов
- простая фабрика (Simple Factory);
- фабричный метод (Factory Method);
- абстрактная фабрика (Abstract Factory);
- строитель (Builder);
- прототип (Prototype);
- одиночка (Singleton).
В объектно-ориентированном программировании (ООП), фабрика — это…
объект для создания других объектов. Формально фабрика — это функция или метод, который возвращает объекты изменяющегося прототипа или класса из некоторого вызова метода, который считается «новым».
SimpleFactory - пример
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; } }
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();
Когда использовать SimpleFactory
Когда создание объекта — это не просто несколько присвоений, а какая-то логика, тогда имеет смысл создать отдельную фабрику вместо повторения одного и того же кода повсюду.
FactoryMethod - это…
порождающий шаблон проектирования, предоставляющий подклассам интерфейс для создания экземпляров некоторого класса. В момент создания наследники могут определить, какой класс создавать. Иными словами, данный шаблон делегирует создание объектов наследникам родительского класса. Это позволяет использовать в коде программы не специфические классы, а манипулировать абстрактными объектами на более высоком уровне.
FactoryMethod - пример…
interface Interviewer
{
public function askQuestions();
}
class Developer implements Interviewer { public function askQuestions() { echo 'Спрашивает про шаблоны проектирования!'; } }
class CommunityExecutive implements Interviewer { public function askQuestions() { echo 'Спрашивает о работе с сообществом'; } }
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(); // Вывод:
Когда использовать FactoryMethod
Полезен, когда есть некоторая общая обработка в классе, но необходимый подкласс динамически определяется во время выполнения. Иными словами, когда клиент не знает, какой именно подкласс ему может понадобиться.
AbstractFactory — это
порождающий шаблон проектирования, предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы (например, для оконного интерфейса он может создавать окна и кнопки). Затем пишутся классы, реализующие этот интерфейс.
AbstractFactory - пример
interface Door
{
public function getDescription();
}
class WoodenDoor implements Door { public function getDescription() { echo 'Я деревянная дверь'; } }
class IronDoor implements Door { public function getDescription() { echo 'Я железная дверь'; } }
interface DoorFittingExpert
{
public function getDescription();
}
class Welder implements DoorFittingExpert { public function getDescription() { echo 'Я работаю только с железными дверьми'; } }
class Carpenter implements DoorFittingExpert { public function getDescription() { echo 'Я работаю только с деревянными дверьми'; } }
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(); // Вывод: Я работаю только с железными дверями
AbstractFactory - когда использовать
Когда есть взаимосвязанные зависимости с не очень простой логикой создания.
Builder - это
порождающий шаблон проектирования, который предоставляет способ создания составного объекта. Предназначен для решения проблемы антипаттерна «Телескопический конструктор».
Builder - пример
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();
Когда использовать Builder
Когда может быть несколько видов объекта и надо избежать «телескопического конструктора». Главное отличие от «фабрики» — это то, что она используется, когда создание занимает один шаг, а «строитель» применяется при множестве шагов.
Prototype - это
Задаёт виды создаваемых объектов с помощью экземпляра-прототипа и создаёт новые объекты путём копирования этого прототипа. Он позволяет уйти от реализации и позволяет следовать принципу «программирование через интерфейсы». В качестве возвращающего типа указывается интерфейс / абстрактный класс на вершине иерархии, а классы-наследники могут подставить туда наследника, реализующего этот тип.
Prototype - пример
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(); // Горная овечка
Prototype - когда использовать
Когда необходим объект, похожий на существующий объект, либо когда создание будет дороже клонирования.
Singleton - это
Одиночка — порождающий шаблон проектирования, гарантирующий, что в однопроцессном приложении будет единственный экземпляр некоторого класса, и предоставляющий глобальную точку доступа к этому экземпляру.
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
Структурные шаблоны
шаблоны проектирования, в которых рассматривается вопрос о том, как из классов и объектов образуются более крупные структуры.
Структурные шаблоны в основном связаны с композицией объектов, другими словами, с тем, как сущности могут использовать друг друга. Ещё одним объяснением было бы то, что они помогают ответить на вопрос «Как создать программный компонент?».
Список структурных шаблонов проектирования
- адаптер (Adapter);
- мост (Bridge);
- компоновщик (Composite);
- декоратор (Decorator);
- фасад (Facade);
- приспособленец (Flyweight);
- заместитель (Proxy).
Adapter - это
структурный шаблон проектирования, предназначенный для организации использования функций объекта, недоступного для модификации, через специально созданный интерфейс.