Статья
Шаблон проектирования "Стратегия"

Шаблон проектирования "Стратегия"

24 июня 2020

Относится к поведенческим шаблонам.

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

Пример на PHP

Рассмотрим сортировку списка объектов, где одна стратегия сортирует по id, другая - по названию.

interface ComparatorInterface
{
    public function compare($a, $b);
}

class IdComparator implements ComparatorInterface
{
    public function compare($a, $b)
    {
        return $a['id'] <=> $b['id'];
    }
}

class TitleComparator implements ComparatorInterface
{
    public function compare($a, $b)
    {
        return $a['title'] <=> $b['title'];
    }
}

class CitiesCollection
{
    private array $cities;

    private ComparatorInterface $comparator;

    public function __construct($cities = [])
    {
        $this->cities = $cities;
    }

    public function setComparator(ComparatorInterface $comparator)
    {
        $this->comparator = $comparator;
    }

    public function sort(): array
    {
        if (!$this->comparator) {
            throw new \Exception('Comparator is not set');
        }

        uasort($this->cities, [$this->comparator, 'compare']);

        return $this->cities;
    }
}

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

$cities = [['id' => 2, 'title' => 'Moscow'], ['id' => 4, 'title' => 'Kaliningrad'], ['id' => 3, 'title' => 'Barcelona']];

$obj = new CitiesCollection($cities);
$obj->setComparator(new IdComparator());
$results = $obj->sort(); // [['id' => 2, 'title' => 'Moscow'], ['id' => 3, 'title' => 'Barcelona'], ['id' => 4, 'title' => 'Kaliningrad']]

$obj->setComparator(new TitleComparator());
$results = $obj->sort(); // [['id' => 3, 'title' => 'Barcelona'], ['id' => 4, 'title' => 'Kaliningrad'], ['id' => 2, 'title' => 'Moscow']]


Пример на Go

package main

import "sort"

type IComparator interface {
   Compare(city1 City, city2 City) bool
}

type City struct {
   id int
   title string
}

type CitiesCollection struct {
   cities []City
   comparator IComparator
}

type IdComparator struct {
}

type TitleComparator struct {
}

func (c *IdComparator) Compare(city1 City, city2 City) bool {
   return city1.id < city2.id
}

func (c *TitleComparator) Compare(city1 City, city2 City) bool {
   return city1.title < city2.title
}

func (c *CitiesCollection) SetCities(cities []City) {
   c.cities = cities
}

func (c *CitiesCollection) SetComparator(comparator IComparator) {
   c.comparator = comparator
}

func (c *CitiesCollection) Sort() []City {
   sortedCities := make([]City, len(c.cities))
   copy(sortedCities, c.cities)

   sort.Slice(sortedCities, func(i, j int) bool {
      return c.comparator.Compare(sortedCities[i], sortedCities[j])
   })

   return sortedCities
}

func main() {
   cities := []City{
      {
         id: 2,
         title: "Moscow",
      },
      {
         id: 4,
         title: "Kaliningrad",
      },
      {
         id: 3,
         title: "Barcelona",
      },
   }

   idComparator := IdComparator{}
   titleComparator := TitleComparator{}

   collection := CitiesCollection{}
   collection.SetCities(cities)
   collection.SetComparator(&idComparator)
   collection.Sort()

   collection.SetComparator(&titleComparator)
   collection.Sort()
}


Источники:
http://designpatternsphp.readthedocs.io/ru/latest/Behavioral/Strategy/README.html
https://habrahabr.ru/company/mailru/blog/325492/