CodingDesignLearningPHP

Strategy Design Pattern

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

Тип поведенческий
Сложность низкая
Примечанение имеет довольно сильного конкурента в лице анонимных функций(?)
Задача

Предположим, что мы разрабатываем приложение для магазина. Как и в каждом магазине, в нашем будут товары, поведение которых будет описывать класс ‘App\Classes\Product’. Проблемой, которую мы будем решать, является вариабельность спобов оплаты товаров. Товар можно оплатить наличным или безналичным расчетом.

Решение с помощью наследования

Для решения данной задачи можно воспользоваться наследованием и создать классы-наследники ProductCashe и ProductCashless, реализующие абстрактный метод Product::charge(), но если у нас уже реализовано наследование и имеются несколько классов-потомков класса Product (например Book, Beer, Fish), то необходимо создать удвоенное количество потомков (BookCashe, BeerCashe, FishCashe, BookCashless, BeerCashless, FishCashless), что уже выглядит пугающе, а нам еще код дублировать и метод оплаты ‘в долг’ реализовывать..

Поэтому воспользуемся композицией (как говорили в 20-м веке: ‘Предпочитайте композицию наследованию’)

Решение с помощью композиции

Вынесем абстрактный метод оплаты в отдельный класс ChargeService, а класс расширим с помощью CashChargeServise и CashlessChargeServise.

В классе Product объявим свойство $chargeService типа ChargeService и инициализируем его (и пару дополнительных свойств) в конструкторе.

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

<?php

namespace App\Classes;

use App\Services\ChargeService;

class Product
{
    private ChargeService $chargeService;
    private string $name;
    private int $price;

    /**
     * Product constructor.
     * @param string $name
     * @param int $price
     * @param ChargeService $chargeService
     */
    public function __construct(string $name, int $price, ChargeService $chargeService)
    {
        $this->chargeService = $chargeService;
        $this->name = $name;
        $this->price = $price;
    }

    /**
     * @return string
     */
    public function charge(): string
    {
        $paymentMethod = $this->chargeService->charge();
        return $this->name . ' ' . $this->price . ' руб. ' . $paymentMethod . "\n";
    }

}
<?php


namespace App\Services;


abstract class ChargeService
{
    /**
     * @return string
     */
    abstract public function charge(): string;
}
<?php


namespace App\Services;


class CashChargeService extends ChargeService
{
    /**
     * @return string
     */
    public function charge(): string
    {
        return 'cash payment';
    }
}
<?php


namespace App\Services;


class CashlessChargeService extends ChargeService
{
    /**
     * @return string
     */
    public function charge(): string
    {
        return 'cashless payment';
    }
}
<?php

use App\Classes\Product;
use App\Services\CashChargeService;
use App\Services\CashlessChargeService;

require('vendor/autoload.php');


$product1 = new Product('Ходыженское', 73, new CashlessChargeService);
$product2 = new Product('Жигулевское', 63, new CashlessChargeService);
$product3 = new Product('Чипсы свин.', 680, new CashChargeService);

print($product1->charge());
print($product2->charge());
print($product3->charge());

выполним index.php:

vagrant@homestead:~/projects/design/strategy$ php index.php 
Ходыженское 73 руб. cashless payment
Жигулевское 63 руб. cashless payment
Чипсы свин. 680 руб. cash payment
vagrant@homestead:~/projects/design/strategy$ 

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

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

Оставить комментарий

avatar
  Подписаться  
Уведомление о