Design PatternsPHPProgramação

Design Pattern – Strategy

Suponha que você tenha criado um relatório no sistema e o cliente precise exportar os dados para diferentes formatos, como CSV e JSON.

Embora a ação seja a mesma (exportar dados) o algoritmo utilizado para gerar cada formato é diferente.

Uma solução simples seria usar vários if ou switch, mas isso violaria o princípio Open/Closed e dificultaria a manutenção do código.

É exatamente nesse cenário que o Strategy Pattern se torna útil.

O Strategy permite encapsular diferentes algoritmos em classes separadas e torná-los intercambiáveis em tempo de execução. Assim, o comportamento pode variar sem modificar a classe que o utiliza.

A classe de contexto (FileExporter) não define por si só a estratégia (CsvFormat ou JsonFormat) que será utilizada. Quem define a estratégia em tempo de execução é o cliente através do método setFormat, que recebe um objeto que implementa a interface IOutputFormat e realiza a exportação dos dados através do método export.

Implementando as estratégias

Primeiro definimos a interface que servirá de base comum para nossas estratégias, a interface IOutputFormat.

<?php

namespace App\Tools\FileExporter;

interface IOutputFormat
{
    public function export(string $fileName, array $data): void;
}Code language: PHP (php)

Em seguida as classes concretas referentes aos algoritmos de importação.

CSV

<?php

namespace App\Tools\FileExporter;

final class CsvFormat implements IOutputFormat
{
    public function export(string $fileName, array $data):void
    {
        $csvArrayData[] = array_keys($data[0]);
        foreach($data as $key => $value){
            $csvArrayData[] = array_values($value);
        }

        header('Content-Type: text/csv; charset=UTF-8');
        header('Content-Disposition: attachment; filename="'.$fileName.'.csv"');
        header('X-Content-Type-Options: nosniff');

        $fp = fopen('php://output', 'w');
        foreach($csvArrayData as $row){
            
            fputcsv($fp, $row);
        }

        fclose($fp);
        exit;
    }
}Code language: PHP (php)

Json

<?php

namespace App\Tools\FileExporter;

final class JsonFormat implements IOutputFormat
{
    public function export(string $fileName, array $data):void
    {
        $content = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

        header('Content-Type: application/json; charset=UTF-8');
        header('Content-Disposition: attachment; filename="'.$fileName.'.json"');
        header('Content-Length: ' . strlen($content));
        header('X-Content-Type-Options: nosniff');

        echo $content;
        exit;
    }
}Code language: PHP (php)

Agora a classe de contexto:

<?php

namespace App\Tools\FileExporter;

class FileExporter
{
    private IOutputFormat $outputFormat;

    public function __construct(IOutputFormat $outputFormat){
       $this->outputFormat = $outputFormat;
    }

    public function export(string $fileName, array $data): void
    {
        $this->outputFormat->build($fileName, $data);
    }

    public function setFormat(IOutputFormat $outputFormat): void
    {
        $this->outputFormat = $outputFormat;
    }
}Code language: PHP (php)

O Strategy Pattern é especialmente útil quando diferentes variações de um comportamento precisam coexistir no sistema sem acoplamento forte entre as implementações.

Além de melhorar a organização do código, esse padrão facilita a extensão da aplicação. Para adicionar um novo formato de exportação, como XML ou XLSX, basta criar uma nova classe que implemente IOutputFormat, sem modificar o FileExporter.

Esse é um exemplo claro de aplicação do princípio Open/Closed.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *