Программирование, Шаблоны проектирования

Шаблон «Стратегия» (Strategy pattern)

В этой статье я постараюсь простым языком объяснить как, где и зачем применять паттерн стратегия.

strategy

Давайте представим вполне конкретную задачу веб-разработчика: импорт данных о пользователях из загруженного файла в базу данных. Файл может быть одного из заранее оговоренных расширений (например, .xls, .doc, .csv, …) и определенным форматом записи данных.


Пример плохого подхода решения задачи

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

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


Чем поможет стратегия?

Плохая новость: шаблон проектирования не решит задачу вместо вас :)

Хорошая новость: в данном случае стратегия поможет красиво решить часть задачи. А именно: определить семейство поддерживаемых форматов импорта, спрятать и убрать их реализацию из клиентского кода (тем самым упростив его), обеспечить легкость добавления поддерживаемых форматов.


Как?

  1. Первым делом определим несколько классов (алгоритмов), каждый из которых будет отвечать за чтение данных из файла определенного формата.
    Также я добавил интерфейс, который будет декларировать наличие метода readFile() для чтения данных в классах.

 

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

 

3. И пример кода, где это все используется:


Итоги

Если теперь прочитать определение на википедии:

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

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

У вас в проекте есть возможность совершать оплату при помощи разных платежных систем?
Есть необходимость сортировать массив данных разными способами?
Нужно экспортировать данные из БД в файл в разных форматах?

Подумайте, возможно, самое время применить стратегию! 😉


Навеяно этим:

http://www.phptherightway.com/pages/Design-Patterns.html

https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D0%B0%D1%82%D0%B5%D0%B3%D0%B8%D1%8F_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)


P.S. Критика приветствуется.

Поделитесь с друзьями или сохраните себе
  •  
  •  
  •  
  •  
  •  
  •  
  •  

3 Comments

  1. Name

    А почему не сделать так без Клиента (FileReader)?

    $file1 = ‘path/to/file.xls’;
    $file2 = ‘path/to/file.doc’;
    // для Xls файла
    $xlsReader = new XlsReader();
    $data = $xlsReader->readFile($file1);
    // для Doc файла
    $docReader = new DocReader();
    $data = $docReader->readFile($file2);

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

    что бы конечный код выглядел минималистично:
    $reader = new FileReader();
    $reader->setReader($file1);
    $data = $reader->getContent($file1);

    или вовсе
    $reader = new FileReader();
    $data = $reader->getContent($file1);

    а иначе… Скажите плз — в чем не прав?

    Reply

Напишите комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *


3 × 2 =