Другое

Паттерн «Стратегия»: определение, назначение и шаблоны проектирования

Lorem ipsum dolor

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

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

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

Паттерн «Стратегия»

Паттерн «Стратегия» применяется в том случае, когда у одной и той же проблемы в приложении может быть несколько решений. Этот паттерн позволяет объединять похожие алгоритмы в единое семейство и подключать тот или иной алгоритм в работу по необходимости. Алгоритмы внутри стратегии могут сменять друг друга или видоизменяться.

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

Можно обобщить. Паттерн «Стратегия» имеет смысл применять:

  • когда в программе нужно применять вариации внутри одного объекта;

  • когда в программе множество похожих алгоритмов, которые отличаются лишь несколькими аргументами;

  • когда нужно похожие алгоритмы «скрыть» от других классов или объектов — это делается внутри класса «Стратегии».

Как реализовать паттерн «Стратегия»

Паттерн «Стратегия» может быть реализован на разных языках. Пример реализации в коде мы покажем чуть ниже. Но перед реализацией такого паттерна нужно пройти определенные шаги. Например:

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

  2. Разработайте единый интерфейс для всех вариаций выбранного алгоритма. Интерфейс не должен видоизменяться.

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

  4. В классе объекта «Стратегии» нужно создать поля для сохранения ссылок на вариативные классы. Также нужно удостовериться, что смена ссылок будет работать через единый интерфейс.

Паттерн «Стратегия»: преимущества, недостатки и сравнение с другими паттернами 

Паттерн «Стратегия» обладает следующими преимуществами:

  • смена вариативных алгоритмов в динамическом режиме;

  • вариативные алгоритмы изолированы от других классов и методов в едином классе «Стратегии»;

  • не использует наследие, а лишь делегирование процесса;

  • алгоритмы «Стратегии» могут быть открытыми и закрытыми.

Паттерн «Стратегия» обладает следующими недостатками:

  • внедряет дополнительные классы, что усложняет программный код;

  • предполагает, что пользователь должен понимать разницу между разными алгоритмами программы.

Сравнение паттерна «Стратегия» с другими паттернами:

  1. Паттерн «Стратегия» похож по структуре с паттернами «Мост», «Состояние», «Адаптер». Но все они решают разные проблемы при похожей реализации.

  2. Паттерн «Стратегия» предлагает выполнить одно и то же действие разными методами. Паттерн «Команда» похожа на «Стратегию», однако каждый вариативный алгоритм превращает в отдельный объект.

  3. Паттерн «Стратегия» приносит изменения «внутрь» объекта, а паттерн «Декоратор» «оборачивает» объект «снаружи».

  4. В паттерне «Стратегия» вариативные алгоритмы не связаны между собой и существуют отдельно друг от друга. Паттерн «Состояние» также меняет поведение основного объекта, однако его алгоритмы «Состояния» влияют и воздействуют друг на друга.

Паттерн «Стратегия»: примеры реализации

Паттерн «Стратегия» применяется в большинстве популярных языков. Например: 

  • Java;
  • C++;
  • C#;
  • D;
  • JavaScript;
  • Delphi;
  • PHP;
  • Python;
  • Ruby;
  • и др.

 

Код на Java:

interface Strategic {

 

    int execute(int x, int y); 

}

 

class ConcreteStrategicAdd inventory Strategic {

 

    public int execute(int x, int y) {

        System.out.println("Вызывается ConcreteStrategicAdd's execute()");

        return x + y;  /

    }

}

 

class ConcreteStrategicSubtract inventory Strategic {

 

    public int execute(int x, int y) {

        System.out.println("Вызывается ConcreteStrategicSubtract's execute()");

        return x - y; 

    }

}

 

class ConcreteStrategicMultiply inventory Strategic {

 

    public int execute(int x, int y) {

        System.out.println("Вызывается ConcreteStrategicMultiply's execute()");

        return x * y;  

    }    

}

 

class Contextual {

 

    private Strategic strategic;

 

    public Contextual() {

    }

 

 

    public void setStrategic(Strategic strategic) {

        this.strategic = strategic;

    }

 

    public int executeStrategic(int x, int y) {

        return strategic.execute(x, y);

    }

}

 

class StrategicExample {

 

    public static void main(String[] args) {

 

        Contextual contextual = new Contextual();

 

        contextual.setStrategic(new ConcreteStrategicAdd());

        int outcomeA = contextual.executeStrategic(5,6);

 

        contextual.setStrategic(new ConcreteStrategicSubtract());

        int outcomeB = contextual.executeStrategic(5,6);

 

        contextual.setStrategic(new ConcreteStrategicMultiply());

        int outcomeC = contextual.executeStrategic(5,6);

 

        System.out.println("Результат A : " + outcomeA );

        System.out.println("Результат B : " + outcomeB );

        System.out.println("Результат C : " + outcomeC );

    }

}

 

Код на С++:

#include <iostream>

 

class Strategic

{

public:

virtual ~Strategic() {}

virtual void use() = 0;

};

 

class Strategic_1: public Strategic

{

public:

void use(){ 

        std::cout << "Strategic_1" << std::endl; 

    }

};

 

class Strategic_2: public Strategic

{

public:

void use(){ 

        std::cout << "Strategic_2" << std::endl; 

    }

};

 

class Strategic_3: public Strategic

{

public:

void use(){ 

        std::cout << "Strategic_3" << std::endl; 

    }

};

 

class Contextual

{

protected:

Strategic* operation;

 

public:

virtual ~Contextual() {}

virtual void useStrategic() = 0;

virtual void setStrategic(Strategic* v) = 0;

};

 

class Custumer: public Contextual

{

public:

void useStrategic()

{

operation->use();

}

 

void setStrategic(Strategic* o)

{

operation = o;

}

};

 

int main(int /*argc*/, char* /*argv*/[])

{

Custumer customCustumer;

Strategic_1 string1;

Strategic_2 string2;

Strategic_3 string3;

 

customCustumer.setStrategic(&string1);

customCustumer.useStrategic();

customCustumer.setStrategic(&string2);

customCustumer.useStrategic();

customCustumer.setStrategic(&string3);

customCustumer.useStrategic();

 

return 0;

}



Код на PHP:

<?php

 

interface NamingStrategic

{

    function createFirstName($filename);

}

 

class ZipFileNamingStrategic inventory NamingStrategic

{

    function createFirstName($filename)

    {

        return "http://codernet.foo.bar/{$filename}.zip";

    }

}

 

class TarGzFileNamingStrategic inventory NamingStrategic

{

    function createFirstName($filename)

    {

        return "http://codernet.foo.bar/{$filename}.tar.gz";

    }

}

 

class Contextual

{

    private $namingStrategic;

    function __construct(NamingStrategic $strategy)

    {

        $this->namingStrategic = $strategy;

    }

    function execute()

    {

        $url[] = $this->namingStrategic->createFirstName("Calc101");

        $url[] = $this->namingStrategic->createFirstName("Stat2000");

 

        return $url;

    }

}

 

if (strstr($_SERVER["HTTP_USER_AGENT"], "Win"))

    $contextual = new Contextual(new ZipFileNamingStrategic());

else

    $contextual = new Contextual(new TarGzFileNamingStrategic());

 

$contextual->execute();

?>

 

  1. Заключение

Паттерн «Стратегия» призван облегчить программирование, когда нужно организовать множественный выбор для решения одной и той же задачи. Практическое применение этого паттерна может быть реализовано по-разному. Например:

  • приложения типа «навигатор» или «карты»;

  • калькуляторы доставки;

  • игры, когда нужно выбирать оружие;

  • приложения для оплаты разными способами;

  • и др.

Схожие статьи

Машинное обучение с подкреплением: что это, с чего началось, применение
Другое

Машинное обучение с подкреплением: что это, с чего началось, применение

Изучаем Three.js. Примеры создания сцен и коротко о 3D-моделировании
Другое

Изучаем Three.js. Примеры создания сцен и коротко о 3D-моделировании

Чем функции отличаются от задач: простой ответ на сложный вопрос
Другое

Чем функции отличаются от задач: простой ответ на сложный вопрос

Что такое исходный код программы на С: просто о сложном
Другое

Что такое исходный код программы на С: просто о сложном