Рубрики
Uncategorized

Супер простая интерпретация шаблонов проектирования

Автор оригинала: David Wong.

Рекомендуемое чтение

  • Дизайн-шаблоны-для-людей Китайская версия (постоянное обновление хранилища github)
  • Ресурсы MongoDB, Библиотеки, Инструменты, Список выбора приложений Китайская версия
  • Какие существуют малоизвестные, но интересные сайты?
  • Записка об Осадном льве
  • Каждый день собирайте отличные проекты на Github
  • Несколько интересных народных сказок
  • Супер Полезный браузер Google, Sublime Text, Phpstorm, Коллекция плагинов Oil Monkey

Супер простое объяснение шаблона дизайна! (Этот проект взят из вилки “дизайн-шаблоны-для-людей”)

Шаблоны проектирования-это решения повторяющихся проблем. Рекомендации по решению определенных проблем . Это не классы, пакеты или библиотеки, которые могут вставлять приложения и ждать, пока произойдет волшебство. Напротив, это рекомендации о том, как решать определенные проблемы в определенных ситуациях.

Шаблоны проектирования-это решения повторяющихся проблем; рекомендации по решению определенных проблем

Википедия описывает их как

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

Обратите внимание на

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

Также обратите внимание, что следующий пример кода-PHP-7, но это не должно вас останавливать, потому что концепции одинаковы.

Типы шаблонов проектирования

  • Тип создания
  • Структурный тип
  • Тип поведения

Проще говоря

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

Википедия

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

  • Простая фабрика
  • Заводской способ
  • Абстрактная фабрика
  • Шаблон конструктора
  • Прототип
  • Синглтон

Простая фабрика

Примеры из реального мира

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

Проще говоря

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

Википедия

В объектно-ориентированном программировании (ООП) фабрика – это объект, используемый для создания других объектов. Формальная фабрика-это функция или метод, который возвращает измененный прототип или объект класса из некоторых вызовов методов, который считается “новым”.

Примеры программирования

Во-первых, у нас есть дверной интерфейс и реализация

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);
    }
}

Затем его можно использовать в качестве

// Make me a door of 100x200
$door = DoorFactory::makeDoor(100, 200);

echo 'Width: ' . $door->getWidth();
echo 'Height: ' . $door->getHeight();

// Make me a door of 50x100
$door2 = DoorFactory::makeDoor(50, 100);

Когда он будет использоваться?

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

Заводской способ

Примеры из реального мира

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

Проще говоря

Это обеспечивает способ делегирования логики создания экземпляров подклассам.

Википедия

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

Примеры программирования

Возьмем, к примеру, вышеприведенного менеджера по найму. Во-первых, у нас есть интерфейс интервьюера и некоторые реализации

interface Interviewer
{
    public function askQuestions();
}

class Developer implements Interviewer
{
    public function askQuestions()
    {
        echo 'Asking about design patterns!';
    }
}

class CommunityExecutive implements Interviewer
{
    public function askQuestions()
    {
        echo 'Asking about community building';
    }
}

Теперь давайте создадим свой собственный. Менеджер по найму

abstract class HiringManager
{

    // Factory method
    abstract protected function makeInterviewer(): Interviewer;

    public function takeInterview()
    {
        $interviewer = $this->makeInterviewer();
        $interviewer->askQuestions();
    }
}

Теперь любой ребенок может продлить и предоставить интервьюеров, в которых он нуждается.

class DevelopmentManager extends HiringManager
{
    protected function makeInterviewer(): Interviewer
    {
        return new Developer();
    }
}

class MarketingManager extends HiringManager
{
    protected function makeInterviewer(): Interviewer
    {
        return new CommunityExecutive();
    }
}

Затем его можно использовать в качестве

$devManager = new DevelopmentManager();
$devManager->takeInterview(); // Output: Asking about design patterns

$marketingManager = new MarketingManager();
$marketingManager->takeInterview(); // Output: Asking about community building.

Когда он будет использоваться?

В классе есть некоторая общая обработка, но полезно динамически определять требуемые подклассы во время выполнения. Другими словами, когда клиент не знает, какие подклассы ему могут понадобиться.

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

Примеры из реального мира

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

Проще говоря

Фабричные заводы; фабрики, которые объединяют людей, но зависят от них, не указывая их конкретные категории.

Википедия

Шаблон абстрактной фабрики предоставляет способ инкапсулировать набор отдельных фабрик с общей темой, но без указания их конкретных классов.

Примеры программирования

Переведите приведенный выше пример с дверью. Во-первых, у нас есть свои собственные. Дверь Интерфейс и некоторые реализации

interface Door
{
    public function getDescription();
}

class WoodenDoor implements Door
{
    public function getDescription()
    {
        echo 'I am a wooden door';
    }
}

class IronDoor implements Door
{
    public function getDescription()
    {
        echo 'I am an iron door';
    }
}

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

interface DoorFittingExpert
{
    public function getDescription();
}

class Welder implements DoorFittingExpert
{
    public function getDescription()
    {
        echo 'I can only fit iron doors';
    }
}

class Carpenter implements DoorFittingExpert
{
    public function getDescription()
    {
        echo 'I can only fit wooden doors';
    }
}

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

interface DoorFactory
{
    public function makeDoor(): Door;
    public function makeFittingExpert(): DoorFittingExpert;
}

// Wooden factory to return carpenter and wooden door
class WoodenDoorFactory implements DoorFactory
{
    public function makeDoor(): Door
    {
        return new WoodenDoor();
    }

    public function makeFittingExpert(): DoorFittingExpert
    {
        return new Carpenter();
    }
}

// Iron door factory to get iron door and the relevant fitting expert
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();  // Output: I am a wooden door
$expert->getDescription(); // Output: I can only fit wooden doors

// Same for Iron Factory
$ironFactory = new IronDoorFactory();

$door = $ironFactory->makeDoor();
$expert = $ironFactory->makeFittingExpert();

$door->getDescription();  // Output: I am an iron door
$expert->getDescription(); // Output: I can only fit iron doors

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

Когда он будет использоваться?

Когда существуют взаимосвязанные зависимости, это включает в себя непростую логику создания

(11) Шаблон конструктора

Примеры из реального мира

Представьте, что вы находитесь в Hardee’s и заказали конкретную транзакцию. Скажем, “Большой Харди”, и они, без сомнения, дали его вам; это пример простой фабрики. Но в некоторых случаях создание логики может включать в себя больше шагов. Например, если вы хотите индивидуальное предложение на метро, у вас есть много вариантов приготовления гамбургера, например, какой хлеб вы хотите? Какой соус вы бы хотели? Какой сыр ты хочешь? В этом случае модель компоновщика была сохранена.

Проще говоря

Позволяет создавать объекты разных стилей, избегая при этом загрязнения конструктора. Это полезно, когда существует несколько стилей объектов. Или есть много шагов, связанных с созданием объектов.

Википедия

Шаблон конструктора-это шаблон проектирования программного обеспечения, созданный объектом, целью которого является поиск решения для антипаттерна масштабируемого конструктора.

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

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

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

Примеры программирования

Рациональной альтернативой является использование шаблона компоновщика. Во-первых, мы собираемся приготовить гамбургеры.

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();

Когда он будет использоваться?

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

(Прототип)

Примеры из реального мира

Помнишь Долли? Клонированные овцы! Давайте не будем вдаваться в подробности, но суть в том, что все дело в клонировании.

Проще говоря

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

Википедия

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

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

Примеры программирования

В PHP его можно легко использовать клонировать

class Sheep
{
    protected $name;
    protected $category;

    public function __construct(string $name, string $category = 'Mountain Sheep')
    {
        $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('Jolly');
echo $original->getName(); // Jolly
echo $original->getCategory(); // Mountain Sheep

// Clone and modify what is required
$cloned = clone $original;
$cloned->setName('Dolly');
echo $cloned->getName(); // Dolly
echo $cloned->getCategory(); // Mountain sheep

Вы также можете использовать магию. __клонирование Для изменения поведения клонирования.

Когда он будет использоваться?

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

(iv) Синглтон

Примеры из реального мира

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

Проще говоря

Убедитесь, что создан только один объект определенного класса.

Википедия

В программной инженерии одноэлементный шаблон-это шаблон проектирования программного обеспечения, который ограничивает создание экземпляра класса объектом. Это очень полезно, когда объект необходим для координации работы всей системы.

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

Примеры программирования

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

final class President
{
    private static $instance;

    private function __construct()
    {
        // Hide the constructor
    }

    public static function getInstance(): President
    {
        if (!self::$instance) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    private function __clone()
    {
        // Disable cloning
    }

    private function __wakeup()
    {
        // Disable unserialize
    }
}

Тогда вы сможете им воспользоваться.

$president1 = President::getInstance();
$president2 = President::getInstance();

var_dump($president1 === $president2); // true

Проще говоря

Структурные шаблоны в основном связаны с составом объектов, или, другими словами, с тем, как сущности используют друг друга. Или другое объяснение заключается в том, что они помогают ответить на вопрос “Как вы создаете программные компоненты?”

Википедия

В программной инженерии структурный шаблон проектирования-это простой способ упростить шаблон проектирования путем определения взаимосвязи между объектами.

  • Режим адаптера
  • Мост
  • Составной
  • Оформитель
  • Фасад
  • Мушиный вес
  • Полномочие

(vii) Режим адаптера

Примеры из реального мира

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

Проще говоря

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

Википедия

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

Примеры программирования

Рассмотрим игру с охотниками, которые охотятся на львов.

Во-первых, у нас есть один. Лев Все типы lions должны реализовывать интерфейсы

interface Lion
{
    public function roar();
}

class AfricanLion implements Lion
{
    public function roar()
    {
    }
}

class AsianLion implements Lion
{
    public function roar()
    {
    }
}

Охотники ожидают чего угодно Лев Можно выполнить поиск по реализации интерфейса.

class Hunter
{
    public function hunt(Lion $lion)
    {
        $lion->roar();
    }
}

Теперь давайте предположим, что мы должны WildDog Добавьте его в нашу игру, чтобы охотники могли преследовать его. Но мы не можем сделать это напрямую, потому что у собак разные интерфейсы. Чтобы сделать его совместимым с нашими охотниками, нам придется создать совместимый адаптер.

// This needs to be added to the game
class WildDog
{
    public function bark()
    {
    }
}

// Adapter around wild dog to make it compatible with our game
class WildDogAdapter implements Lion
{
    protected $dog;

    public function __construct(WildDog $dog)
    {
        $this->dog = $dog;
    }

    public function roar()
    {
        $this->dog->bark();
    }
}

А теперь Дикая собака Его можно использовать в наших играх. Адаптер Для Дикой собаки

$wildDog = new WildDog();
$wildDogAdapter = new WildDogAdapter($wildDog);

$hunter = new Hunter();
$hunter->hunt($wildDogAdapter);

(vii) Мостовой режим

Примеры из реального мира

Учтите, что у вас есть веб-сайт с разными страницами, вы должны разрешить пользователям изменять темы. Что бы ты сделал? Создайте несколько копий каждой страницы для каждой темы или вы просто создаете отдельные темы и загружаете их в соответствии с предпочтениями пользователя? Режим моста позволяет выполнить второй IE

Проще говоря,

Режим моста-это комбинации, которые имеют приоритет над наследованием. Детали реализации перемещаются из иерархии в другой объект с отдельной иерархией.

Википедия

Шаблон наведения мостов-это шаблон проектирования, используемый в разработке программного обеспечения, направленный на “отделение абстракции от ее реализации, чтобы они могли изменяться независимо”.

Примеры программирования

Переведите пример нашей веб-страницы сверху. Здесь у нас есть веб-страница иерархическая структура

interface WebPage
{
    public function __construct(Theme $theme);
    public function getContent();
}

class About implements WebPage
{
    protected $theme;

    public function __construct(Theme $theme)
    {
        $this->theme = $theme;
    }

    public function getContent()
    {
        return "About page in " . $this->theme->getColor();
    }
}

class Careers implements WebPage
{
    protected $theme;

    public function __construct(Theme $theme)
    {
        $this->theme = $theme;
    }

    public function getContent()
    {
        return "Careers page in " . $this->theme->getColor();
    }
}

И отдельная тематическая иерархия

interface Theme
{
    public function getColor();
}

class DarkTheme implements Theme
{
    public function getColor()
    {
        return 'Dark Black';
    }
}
class LightTheme implements Theme
{
    public function getColor()
    {
        return 'Off white';
    }
}
class AquaTheme implements Theme
{
    public function getColor()
    {
        return 'Light blue';
    }
}

И эти две иерархии

$darkTheme = new DarkTheme();

$about = new About($darkTheme);
$careers = new Careers($darkTheme);

echo $about->getContent(); // "About page in Dark Black";
echo $careers->getContent(); // "Careers page in Dark Black";

Составной

Примеры из реального мира

Каждая организация состоит из сотрудников. У каждого сотрудника одна и та же функция, то есть зарплата, некоторые обязанности, он может кому-то отчитываться или не отчитываться, у него могут быть или не быть подчиненные и т.д.

Проще говоря

Составной режим позволяет клиентам обрабатывать отдельные объекты единым способом.

Википедия

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

Примеры программирования

Возьмем, к примеру, вышеперечисленных сотрудников. У нас здесь разные типы сотрудников.

interface Employee
{
    public function __construct(string $name, float $salary);
    public function getName(): string;
    public function setSalary(float $salary);
    public function getSalary(): float;
    public function getRoles(): array;
}

class Developer implements Employee
{
    protected $salary;
    protected $name;
    protected $roles;
    
    public function __construct(string $name, float $salary)
    {
        $this->name = $name;
        $this->salary = $salary;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setSalary(float $salary)
    {
        $this->salary = $salary;
    }

    public function getSalary(): float
    {
        return $this->salary;
    }

    public function getRoles(): array
    {
        return $this->roles;
    }
}

class Designer implements Employee
{
    protected $salary;
    protected $name;
    protected $roles;

    public function __construct(string $name, float $salary)
    {
        $this->name = $name;
        $this->salary = $salary;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setSalary(float $salary)
    {
        $this->salary = $salary;
    }

    public function getSalary(): float
    {
        return $this->salary;
    }

    public function getRoles(): array
    {
        return $this->roles;
    }
}

Тогда у нас есть организация, состоящая из нескольких различных типов сотрудников.

class Organization
{
    protected $employees;

    public function addEmployee(Employee $employee)
    {
        $this->employees[] = $employee;
    }

    public function getNetSalaries(): float
    {
        $netSalary = 0;

        foreach ($this->employees as $employee) {
            $netSalary += $employee->getSalary();
        }

        return $netSalary;
    }
}

Затем его можно использовать в качестве

// Prepare the employees
$john = new Developer('John Doe', 12000);
$jane = new Designer('Jane Doe', 15000);

// Add them to organization
$organization = new Organization();
$organization->addEmployee($john);
$organization->addEmployee($jane);

echo "Net salaries: " . $organization->getNetSalaries(); // Net Salaries: 27000

Оформитель

Примеры из реального мира

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

Проще говоря

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

Википедия

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

Примеры программирования

Давайте возьмем в качестве примера кофе. Во-первых, у нас есть простой интерфейс кофе.

interface Coffee
{
    public function getCost();
    public function getDescription();
}

class SimpleCoffee implements Coffee
{
    public function getCost()
    {
        return 10;
    }

    public function getDescription()
    {
        return 'Simple coffee';
    }
}

Мы хотим сделать код расширяемым, чтобы можно было изменять его при необходимости. Давайте сделаем некоторые дополнения (декораторы)

class MilkCoffee implements Coffee
{
    protected $coffee;

    public function __construct(Coffee $coffee)
    {
        $this->coffee = $coffee;
    }

    public function getCost()
    {
        return $this->coffee->getCost() + 2;
    }

    public function getDescription()
    {
        return $this->coffee->getDescription() . ', milk';
    }
}

class WhipCoffee implements Coffee
{
    protected $coffee;

    public function __construct(Coffee $coffee)
    {
        $this->coffee = $coffee;
    }

    public function getCost()
    {
        return $this->coffee->getCost() + 5;
    }

    public function getDescription()
    {
        return $this->coffee->getDescription() . ', whip';
    }
}

class VanillaCoffee implements Coffee
{
    protected $coffee;

    public function __construct(Coffee $coffee)
    {
        $this->coffee = $coffee;
    }

    public function getCost()
    {
        return $this->coffee->getCost() + 3;
    }

    public function getDescription()
    {
        return $this->coffee->getDescription() . ', vanilla';
    }
}

А теперь давайте выпьем по чашечке кофе.

$someCoffee = new SimpleCoffee();
echo $someCoffee->getCost(); // 10
echo $someCoffee->getDescription(); // Simple Coffee

$someCoffee = new MilkCoffee($someCoffee);
echo $someCoffee->getCost(); // 12
echo $someCoffee->getDescription(); // Simple Coffee, milk

$someCoffee = new WhipCoffee($someCoffee);
echo $someCoffee->getCost(); // 17
echo $someCoffee->getDescription(); // Simple Coffee, milk, whip

$someCoffee = new VanillaCoffee($someCoffee);
echo $someCoffee->getCost(); // 20
echo $someCoffee->getDescription(); // Simple Coffee, milk, whip, vanilla

(ii) Фасад

Примеры из реального мира

Как вы включаете компьютер? “Нажми кнопку питания”, – сказал ты! Это то, во что вы верите, потому что вы используете простой интерфейс, который компьютер предоставляет снаружи и внутри, ему нужно многое сделать, чтобы достичь этого. Простой интерфейс этой сложной подсистемы представляет собой фасад.

Проще говоря

Модель фасада обеспечивает упрощенный интерфейс для сложных подсистем.

Википедия

Внешний вид-это объект, который обеспечивает упрощенный интерфейс для большего объема кода, такого как библиотека классов.

Примеры программирования

Посмотрите на пример вашего компьютера сверху. Здесь у нас есть компьютерные уроки.

class Computer
{
    public function getElectricShock()
    {
        echo "Ouch!";
    }

    public function makeSound()
    {
        echo "Beep beep!";
    }

    public function showLoadingScreen()
    {
        echo "Loading..";
    }

    public function bam()
    {
        echo "Ready to be used!";
    }

    public function closeEverything()
    {
        echo "Bup bup bup buzzzz!";
    }

    public function sooth()
    {
        echo "Zzzzz";
    }

    public function pullCurrent()
    {
        echo "Haaah!";
    }
}

Здесь у нас есть фасад

class ComputerFacade
{
    protected $computer;

    public function __construct(Computer $computer)
    {
        $this->computer = $computer;
    }

    public function turnOn()
    {
        $this->computer->getElectricShock();
        $this->computer->makeSound();
        $this->computer->showLoadingScreen();
        $this->computer->bam();
    }

    public function turnOff()
    {
        $this->computer->closeEverything();
        $this->computer->pullCurrent();
        $this->computer->sooth();
    }
}

Теперь используйте фасад

$computer = new ComputerFacade(new Computer());
$computer->turnOn(); // Ouch! Beep beep! Loading.. Ready to be used!
$computer->turnOff(); // Bup bup buzzz! Haah! Zzzzz

Мушиный вес

Примеры из реального мира

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

Проще говоря

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

Википедия

Flyweight-это режим разработки программного обеспечения в компьютерном программировании. Flweight-это объект, который минимизирует использование памяти за счет обмена как можно большим количеством данных с другими аналогичными объектами; это способ использования объектов в больших количествах, когда простые повторяющиеся представления будут использовать недопустимый объем памяти.

Процедурный пример

Переведите наши примеры чая сверху. Во-первых, у нас есть чай и чайные сервизы.

// Anything that will be cached is flyweight.
// Types of tea here will be flyweights.
class KarakTea
{
}

// Acts as a factory and saves the tea
class TeaMaker
{
    protected $availableTea = [];

    public function make($preference)
    {
        if (empty($this->availableTea[$preference])) {
            $this->availableTea[$preference] = new KarakTea();
        }

        return $this->availableTea[$preference];
    }
}

Тогда у нас есть Чайная Принимаем заказы и обслуживаем их

class TeaShop
{
    protected $orders;
    protected $teaMaker;

    public function __construct(TeaMaker $teaMaker)
    {
        $this->teaMaker = $teaMaker;
    }

    public function takeOrder(string $teaType, int $table)
    {
        $this->orders[$table] = $this->teaMaker->make($teaType);
    }

    public function serve()
    {
        foreach ($this->orders as $table => $tea) {
            echo "Serving tea to table# " . $table;
        }
    }
}

Его можно использовать следующим образом

$teaMaker = new TeaMaker();
$shop = new TeaShop($teaMaker);

$shop->takeOrder('less sugar', 1);
$shop->takeOrder('more milk', 2);
$shop->takeOrder('without sugar', 5);

$shop->serve();
// Serving tea to table# 1
// Serving tea to table# 2
// Serving tea to table# 5

Полномочие

Примеры из реального мира

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

Проще говоря

Используя шаблон прокси, класс представляет функциональность другого класса.

Википедия

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

Примеры программирования

Посмотрите на наш пример с защитной дверью сверху. Прежде всего, у нас есть интерфейс двери и реализация двери.

interface Door
{
    public function open();
    public function close();
}

class LabDoor implements Door
{
    public function open()
    {
        echo "Opening lab door";
    }

    public function close()
    {
        echo "Closing the lab door";
    }
}

Тогда у нас есть агент, который защитит любую дверь, какую мы захотим.

class SecuredDoor
{
    protected $door;

    public function __construct(Door $door)
    {
        $this->door = $door;
    }

    public function open($password)
    {
        if ($this->authenticate($password)) {
            $this->door->open();
        } else {
            echo "Big no! It ain't possible.";
        }
    }

    public function authenticate($password)
    {
        return $password === '[email protected]';
    }

    public function close()
    {
        $this->door->close();
    }
}

Вот как это используется

$door = new SecuredDoor(new LabDoor());
$door->open('invalid'); // Big no! It ain't possible.

$door->open('[email protected]'); // Opening lab door
$door->close(); // Closing lab door

Другим примером является реализация картографа данных. Например, недавно я использовал этот шаблон для создания ODM (картографирования объектных данных) для MongoDB, и я написал прокси-сервер вокруг класса Mongo, используя магические методы. __вызов () . Все вызовы методов передаются исходному классу Монтгомери, и результат извлекается обратно, потому что это так, но в этом случае найти или Найти Данные сопоставляются с требуемыми объектами класса и вместо этого объект возвращает Курсор .

Проще говоря

Он фокусируется на распределении обязанностей между объектами. Они отличаются от структурных шаблонов тем, что они не только определяют структуры, но и описывают шаблоны обмена сообщениями/коммуникации между ними. Или, другими словами, они помогают ответить на вопрос “Как вы запускаете поведение в программных компонентах?”

Википедия

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

  • Цепочка обязанностей
  • Режим командной строки
  • Шаблон итератора
  • Посредник
  • Сувенир
  • Наблюдатель
  • Режим посетителя
  • Стратегия
  • Государство
  • Метод шаблона

(vii) Цепочка обязанностей

Примеры из реального мира

Например, у вас есть три способа оплаты.( A , B и C ) Установите в своей учетной записи; у каждого из них свой номер. А Есть 100 долларов. B С 300 долларами и C С 1000 долларами и предпочтениями в оплате, выбранными как A снова B Затем C 。 Вы пытаетесь купить что-то стоимостью 210 долларов. Используйте цепочку ответственности, прежде всего A Он проверяет, можно ли приобрести учетную запись, и если да, то она будет куплена, и цепочка будет разорвана. Если нет, запрос будет продолжен с учетной записью. B Проверьте сумму, если цепочка будет разорвана, в противном случае запрос будет продолжать перенаправляться до тех пор, пока не будут найдены соответствующие процедуры обработки. Ad locum A , B и C Это звено цепи, все явление-это цепь ответственности.

Проще говоря

Это помогает построить серию объектов. Запрос поступает с одного конца и продолжается от одного объекта к другому, пока не будет найден соответствующий обработчик.

Википедия

В объектно-ориентированном проектировании шаблон цепочки ответственности-это шаблон проектирования, состоящий из commandobjectsource и ряда объектов обработки. Каждый объект обработки содержит логику, определяющую тип объекта команды, который он может обрабатывать; остальное передается следующему объекту обработки в цепочке.

Примеры программирования

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

abstract class Account
{
    protected $successor;
    protected $balance;

    public function setNext(Account $account)
    {
        $this->successor = $account;
    }

    public function pay(float $amountToPay)
    {
        if ($this->canPay($amountToPay)) {
            echo sprintf('Paid %s using %s' . PHP_EOL, $amountToPay, get_called_class());
        } elseif ($this->successor) {
            echo sprintf('Cannot pay using %s. Proceeding ..' . PHP_EOL, get_called_class());
            $this->successor->pay($amountToPay);
        } else {
            throw new Exception('None of the accounts have enough balance');
        }
    }

    public function canPay($amount): bool
    {
        return $this->balance >= $amount;
    }
}

class Bank extends Account
{
    protected $balance;

    public function __construct(float $balance)
    {
        $this->balance = $balance;
    }
}

class Paypal extends Account
{
    protected $balance;

    public function __construct(float $balance)
    {
        $this->balance = $balance;
    }
}

class Bitcoin extends Account
{
    protected $balance;

    public function __construct(float $balance)
    {
        $this->balance = $balance;
    }
}

Теперь давайте воспользуемся цепочкой подготовки ссылок, определенной выше (банк, Paypal, Биткоин).

// Let's prepare a chain like below
//      $bank->$paypal->$bitcoin
//
// First priority bank
//      If bank can't pay then paypal
//      If paypal can't pay then bit coin

$bank = new Bank(100);          // Bank with balance 100
$paypal = new Paypal(200);      // Paypal with balance 200
$bitcoin = new Bitcoin(300);    // Bitcoin with balance 300

$bank->setNext($paypal);
$paypal->setNext($bitcoin);

// Let's try to pay using the first priority i.e. bank
$bank->pay(259);

// Output will be
// ==============
// Cannot pay using bank. Proceeding ..
// Cannot pay using paypal. Proceeding ..:
// Paid 259 using Bitcoin!

(x) Режим командной строки (Команда)

Примеры из реального мира

Распространенный пример – когда вы делаете заказ в ресторане. Вы (то есть) Клиент ) Спросите официанта (т. е. Вызывающего ) Возьмите немного еды (т. е. Команда Официант просто переадресует запрос шеф-повару. Приемник Шеф-повар знает, что и как готовить. Другим примером является использование пульта дистанционного управления. Клиент Открытое (то есть) Командное ) телевидение. Получатель `Вызывающий`

Проще говоря

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

Википедия

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

Примеры программирования

Во-первых, у нас есть приемник, который может выполнять все операции, которые могут быть выполнены.

// Receiver
class Bulb
{
    public function turnOn()
    {
        echo "Bulb has been lit";
    }

    public function turnOff()
    {
        echo "Darkness!";
    }
}

Затем у нас есть интерфейс, каждая команда будет реализована, а затем у нас есть набор команд.

interface Command
{
    public function execute();
    public function undo();
    public function redo();
}

// Command
class TurnOn implements Command
{
    protected $bulb;

    public function __construct(Bulb $bulb)
    {
        $this->bulb = $bulb;
    }

    public function execute()
    {
        $this->bulb->turnOn();
    }

    public function undo()
    {
        $this->bulb->turnOff();
    }

    public function redo()
    {
        $this->execute();
    }
}

class TurnOff implements Command
{
    protected $bulb;

    public function __construct(Bulb $bulb)
    {
        $this->bulb = $bulb;
    }

    public function execute()
    {
        $this->bulb->turnOff();
    }

    public function undo()
    {
        $this->bulb->turnOn();
    }

    public function redo()
    {
        $this->execute();
    }
}

Тогда мы Вызывающий Взаимодействует с клиентом для обработки любых команд

// Invoker
class RemoteControl
{
    public function submit(Command $command)
    {
        $command->execute();
    }
}

Наконец, давайте посмотрим, как мы можем использовать его на стороне клиента.

$bulb = new Bulb();

$turnOn = new TurnOn($bulb);
$turnOff = new TurnOff($bulb);

$remote = new RemoteControl();
$remote->submit($turnOn); // Bulb has been lit!
$remote->submit($turnOff); // Darkness!

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

Режим итератора

Примеры из реального мира

Старые радиоустройства будут хорошим примером итератора, в котором пользователи могут начать с канала, а затем использовать кнопку “Следующий” или “предыдущий” для просмотра соответствующего канала. Или возьмите, например, MP3-плеер или телевизор. Вы можете нажать кнопку “Далее” и последнюю кнопку, чтобы просмотреть непрерывные каналы. Другими словами, они оба предоставляют интерфейс для перебора своих каналов, песен или радиостанций.

Проще говоря

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

Википедия

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

Процедурный пример

В PHP легко реализовать использование SPL (стандартной библиотеки PHP). Переведите наш пример с радио сверху. Прежде всего, у нас есть Радиостанция

class RadioStation
{
    protected $frequency;

    public function __construct(float $frequency)
    {
        $this->frequency = $frequency;
    }

    public function getFrequency(): float
    {
        return $this->frequency;
    }
}

Тогда у нас есть итератор.

use Countable;
use Iterator;

class StationList implements Countable, Iterator
{
    /** @var RadioStation[] $stations */
    protected $stations = [];

    /** @var int $counter */
    protected $counter;

    public function addStation(RadioStation $station)
    {
        $this->stations[] = $station;
    }

    public function removeStation(RadioStation $toRemove)
    {
        $toRemoveFrequency = $toRemove->getFrequency();
        $this->stations = array_filter($this->stations, function (RadioStation $station) use ($toRemoveFrequency) {
            return $station->getFrequency() !== $toRemoveFrequency;
        });
    }

    public function count(): int
    {
        return count($this->stations);
    }

    public function current(): RadioStation
    {
        return $this->stations[$this->counter];
    }

    public function key()
    {
        return $this->counter;
    }

    public function next()
    {
        $this->counter++;
    }

    public function rewind()
    {
        $this->counter = 0;
    }

    public function valid(): bool
    {
        return isset($this->stations[$this->counter]);
    }
}

Затем его можно использовать в качестве

$stationList = new StationList();

$stationList->addStation(new RadioStation(89));
$stationList->addStation(new RadioStation(101));
$stationList->addStation(new RadioStation(102));
$stationList->addStation(new RadioStation(103.2));

foreach($stationList as $station) {
    echo $station->getFrequency() . PHP_EOL;
}

$stationList->removeStation(new RadioStation(89)); // Will remove station 89

(iv) Модель посредника

Примеры из реального мира

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

Проще говоря

Шаблон посредника добавляет сторонние объекты (называемые посредниками) для управления взаимодействием между двумя объектами (называемыми коллегами). Это помогает уменьшить связь между классами, которые взаимодействуют друг с другом. Потому что теперь им не нужно знать о реализации друг друга.

Википедия

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

Примеры программирования

Это самый простой пример обмена сообщениями между комнатой чата (т. е. посредником) и пользователем (т. е. коллегой).

Во-первых, у нас есть посредник, чат-комната.

interface ChatRoomMediator 
{
    public function showMessage(User $user, string $message);
}

// Mediator
class ChatRoom implements ChatRoomMediator
{
    public function showMessage(User $user, string $message)
    {
        $time = date('M d, y H:i');
        $sender = $user->getName();

        echo $time . '[' . $sender . ']:' . $message;
    }
}

Тогда у нас есть наши пользователи, наши коллеги.

class User {
    protected $name;
    protected $chatMediator;

    public function __construct(string $name, ChatRoomMediator $chatMediator) {
        $this->name = $name;
        $this->chatMediator = $chatMediator;
    }

    public function getName() {
        return $this->name;
    }

    public function send($message) {
        $this->chatMediator->showMessage($this, $message);
    }
}

И использование

$mediator = new ChatRoom();

$john = new User('John Doe', $mediator);
$jane = new User('Jane Doe', $mediator);

$john->send('Hi there!');
$jane->send('Hey!');

// Output will be
// Feb 14, 10:58 [John]: Hi there!
// Feb 14, 10:58 [Jane]: Hey!

(ix) Модель меморандума (Памятная записка)

Примеры из реального мира

Возьмем в качестве примера калькулятор (т. е. инициатор). Всякий раз, когда выполняется какой-либо расчет, окончательный расчет сохраняется в памяти (т. Е. в сувенире), чтобы вы могли вернуться к нему и восстановить его с помощью какой-либо кнопки управления (т. Е. смотрителя).

Проще говоря

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

Википедия

Шаблон memento-это шаблон разработки программного обеспечения, который обеспечивает возможность восстановления объекта в его предыдущее состояние (путем отката).

Обычно это полезно, когда вам нужно предоставить некоторые функции отмены.

Примеры программирования

Давайте приведем пример текстового редактора, который время от времени сохраняет состояние, и вы можете восстановить его по мере необходимости.

Во-первых, у нас есть объект memento, который может сохранять состояние редактора

class EditorMemento
{
    protected $content;

    public function __construct(string $content)
    {
        $this->content = $content;
    }

    public function getContent()
    {
        return $this->content;
    }
}

Затем у нас есть наш редактор, создатель предстоящего объекта memento.

class Editor
{
    protected $content = '';

    public function type(string $words)
    {
        $this->content = $this->content . ' ' . $words;
    }

    public function getContent()
    {
        return $this->content;
    }

    public function save()
    {
        return new EditorMemento($this->content);
    }

    public function restore(EditorMemento $memento)
    {
        $this->content = $memento->getContent();
    }
}

Затем его можно использовать в качестве

$editor = new Editor();

// Type some stuff
$editor->type('This is the first sentence.');
$editor->type('This is second.');

// Save the state to restore to : This is the first sentence. This is second.
$saved = $editor->save();

// Type some more
$editor->type('And this is third.');

// Output: Content before Saving
echo $editor->getContent(); // This is the first sentence. This is second. And this is third.

// Restoring to last saved state
$editor->restore($saved);

$editor->getContent(); // This is the first sentence. This is second.

(vii) Модель наблюдателя

Примеры из реального мира

Хорошим примером являются соискатели, которые подписываются на веб-сайты, публикующие вакансии, и получают уведомления о соответствующих возможностях трудоустройства.

Проще говоря

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

Википедия

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

Процедурный пример

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

class JobPost
{
    protected $title;

    public function __construct(string $title)
    {
        $this->title = $title;
    }

    public function getTitle()
    {
        return $this->title;
    }
}

class JobSeeker implements Observer
{
    protected $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function onJobPosted(JobPost $job)
    {
        // Do something with the job posting
        echo 'Hi ' . $this->name . '! New job posted: '. $job->getTitle();
    }
}

Затем мы найдем информацию о наборе персонала, на которую будут подписываться соискатели.

class EmploymentAgency implements Observable
{
    protected $observers = [];

    protected function notify(JobPost $jobPosting)
    {
        foreach ($this->observers as $observer) {
            $observer->onJobPosted($jobPosting);
        }
    }

    public function attach(Observer $observer)
    {
        $this->observers[] = $observer;
    }

    public function addJob(JobPost $jobPosting)
    {
        $this->notify($jobPosting);
    }
}

Затем его можно использовать в качестве

// Create subscribers
$johnDoe = new JobSeeker('John Doe');
$janeDoe = new JobSeeker('Jane Doe');

// Create publisher and attach subscribers
$jobPostings = new EmploymentAgency();
$jobPostings->attach($johnDoe);
$jobPostings->attach($janeDoe);

// Add a new job and see if subscribers get notified
$jobPostings->addJob(new JobPost('Software Engineer'));

// Output
// Hi John Doe! New job posted: Software Engineer
// Hi Jane Doe! New job posted: Software Engineer

Режим посетителя

Примеры из реального мира

Подумайте о людях, которые едут в Дубай. Им нужен только один способ (виза) для въезда в Дубай. Когда они прибудут, они могут посетить любую точку Дубая самостоятельно, не спрашивая разрешения или выполняя какую-либо работу, чтобы они могли посетить любую точку Дубая; сообщите им место, где они могут его посетить. Режим посетителя позволяет вам это сделать. Это поможет вам добавить места для посещения, чтобы они могли получить доступ к как можно большему количеству мест без какой-либо работы.

Проще говоря

Режим посетителя позволяет добавлять дополнительные операции к объектам без их изменения.

Википедия

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

Процедурный пример

Давайте приведем пример моделирования зоопарка. У нас есть несколько разных животных. Мы должны заставить их звучать. Давайте переведем это в режим посетителя

// Visitee
interface Animal
{
    public function accept(AnimalOperation $operation);
}

// Visitor
interface AnimalOperation
{
    public function visitMonkey(Monkey $monkey);
    public function visitLion(Lion $lion);
    public function visitDolphin(Dolphin $dolphin);
}

Тогда у нас есть реализация животных.

class Monkey implements Animal
{
    public function shout()
    {
        echo 'Ooh oo aa aa!';
    }

    public function accept(AnimalOperation $operation)
    {
        $operation->visitMonkey($this);
    }
}

class Lion implements Animal
{
    public function roar()
    {
        echo 'Roaaar!';
    }

    public function accept(AnimalOperation $operation)
    {
        $operation->visitLion($this);
    }
}

class Dolphin implements Animal
{
    public function speak()
    {
        echo 'Tuut tuttu tuutt!';
    }

    public function accept(AnimalOperation $operation)
    {
        $operation->visitDolphin($this);
    }
}

Давайте сделаем так, чтобы наши посетители стали реальностью

class Speak implements AnimalOperation
{
    public function visitMonkey(Monkey $monkey)
    {
        $monkey->shout();
    }

    public function visitLion(Lion $lion)
    {
        $lion->roar();
    }

    public function visitDolphin(Dolphin $dolphin)
    {
        $dolphin->speak();
    }
}

Затем его можно использовать в качестве

$monkey = new Monkey();
$lion = new Lion();
$dolphin = new Dolphin();

$speak = new Speak();

$monkey->accept($speak);    // Ooh oo aa aa!    
$lion->accept($speak);      // Roaaar!
$dolphin->accept($speak);   // Tuut tutt tuutt!

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

class Jump implements AnimalOperation
{
    public function visitMonkey(Monkey $monkey)
    {
        echo 'Jumped 20 feet high! on to the tree!';
    }

    public function visitLion(Lion $lion)
    {
        echo 'Jumped 7 feet! Back on the ground!';
    }

    public function visitDolphin(Dolphin $dolphin)
    {
        echo 'Walked on water a little and disappeared';
    }
}

И для использования

$jump = new Jump();

$monkey->accept($speak);   // Ooh oo aa aa!
$monkey->accept($jump);    // Jumped 20 feet high! on to the tree!

$lion->accept($speak);     // Roaaar!
$lion->accept($jump);      // Jumped 7 feet! Back on the ground!

$dolphin->accept($speak);  // Tuut tutt tuutt!
$dolphin->accept($jump);   // Walked on water a little and disappeared

(vii) Стратегия

Примеры из реального мира

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

Проще говоря

Режим политики позволяет переключать алгоритмы или политики в зависимости от обстоятельств.

Википедия

В компьютерном программировании шаблон политики (также известный как шаблон политики) – это шаблон разработки программного обеспечения для поведения, который может выбирать поведение алгоритма во время выполнения.

Процедурный пример

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

interface SortStrategy
{
    public function sort(array $dataset): array;
}

class BubbleSortStrategy implements SortStrategy
{
    public function sort(array $dataset): array
    {
        echo "Sorting using bubble sort";

        // Do sorting
        return $dataset;
    }
}

class QuickSortStrategy implements SortStrategy
{
    public function sort(array $dataset): array
    {
        echo "Sorting using quick sort";

        // Do sorting
        return $dataset;
    }
}

Тогда наши клиенты будут использовать любую стратегию.

class Sorter
{
    protected $sorter;

    public function __construct(SortStrategy $sorter)
    {
        $this->sorter = $sorter;
    }

    public function sort(array $dataset): array
    {
        return $this->sorter->sort($dataset);
    }
}

Его можно использовать как

И его можно использовать в качестве

$dataset = [1, 5, 4, 3, 2, 8];

$sorter = new Sorter(new BubbleSortStrategy());
$sorter->sort($dataset); // Output : Sorting using bubble sort

$sorter = new Sorter(new QuickSortStrategy());
$sorter->sort($dataset); // Output : Sorting using quick sort

(viii) Государство

Примеры из реального мира

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

Проще говоря

Это позволяет изменять поведение класса при изменении состояния.

Википедия

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

Процедурный пример

Давайте возьмем в качестве примера текстовый редактор, который позволяет изменять состояние вводимого текста, то есть, если вы выбираете жирный шрифт, вы начинаете отображать его полужирным шрифтом, если курсивом, курсивом и т.д.

Во-первых, у нас есть интерфейсы состояний и некоторые реализации состояний

interface WritingState
{
    public function write(string $words);
}

class UpperCase implements WritingState
{
    public function write(string $words)
    {
        echo strtoupper($words);
    }
}

class LowerCase implements WritingState
{
    public function write(string $words)
    {
        echo strtolower($words);
    }
}

class DefaultText implements WritingState
{
    public function write(string $words)
    {
        echo $words;
    }
}

Тогда у нас есть редакторы.

class TextEditor
{
    protected $state;

    public function __construct(WritingState $state)
    {
        $this->state = $state;
    }

    public function setState(WritingState $state)
    {
        $this->state = $state;
    }

    public function type(string $words)
    {
        $this->state->write($words);
    }
}

Затем его можно использовать в качестве

$editor = new TextEditor(new DefaultText());

$editor->type('First line');

$editor->setState(new UpperCase());

$editor->type('Second line');
$editor->type('Third line');

$editor->setState(new LowerCase());

$editor->type('Fourth line');
$editor->type('Fifth line');

// Output:
// First line
// SECOND LINE
// THIRD LINE
// fourth line
// fifth line

(x) Шаблонный метод

Примеры из реального мира

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

  • Основа для подготовки дома
  • Стройте стены
  • Добавить крышу
  • Добавление других этажей

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

Проще говоря

Методы шаблонов определяют структуру выполнения алгоритма, но откладывают выполнение этих шагов до подклассов.

Википедия

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

Примеры программирования

Представьте, что у нас есть инструмент сборки, который может помочь нам тестировать, связывать, создавать, создавать отчеты о сборке (отчеты о покрытии кода, отчеты о планировании и т.д.) И развертывать наши приложения на тестовом сервере.

Во-первых, у нас есть базовый класс, который определяет скелет алгоритма сборки

abstract class Builder
{

    // Template method
    final public function build()
    {
        $this->test();
        $this->lint();
        $this->assemble();
        $this->deploy();
    }

    abstract public function test();
    abstract public function lint();
    abstract public function assemble();
    abstract public function deploy();
}

Тогда мы сможем достичь нашей реализации.

class AndroidBuilder extends Builder
{
    public function test()
    {
        echo 'Running android tests';
    }

    public function lint()
    {
        echo 'Linting the android code';
    }

    public function assemble()
    {
        echo 'Assembling the android build';
    }

    public function deploy()
    {
        echo 'Deploying android build to server';
    }
}

class IosBuilder extends Builder
{
    public function test()
    {
        echo 'Running ios tests';
    }

    public function lint()
    {
        echo 'Linting the ios code';
    }

    public function assemble()
    {
        echo 'Assembling the ios build';
    }

    public function deploy()
    {
        echo 'Deploying ios build to server';
    }
}

Затем его можно использовать в качестве

$androidBuilder = new AndroidBuilder();
$androidBuilder->build();

// Output:
// Running android tests
// Linting the android code
// Assembling the android build
// Deploying android build to server

$iosBuilder = new IosBuilder();
$iosBuilder->build();

// Output:
// Running ios tests
// Linting the ios code
// Assembling the ios build
// Deploying ios build to server

(vi) Для подведения итогов

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