1.9. Strategy

1.9.1. Intent

According to the Gang of Four, the Strategy pattern is a way to “define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it” (Design Patterns: Elements of Reusable Object-Oriented Software, 2013, p. 315).

1.9.2. When to use it?

The Strategy pattern should be used in various cases:

  • several classes differ only in their behavior (Strategy pattern lets you “attach” a behavior to a class)
  • different variants of an algorithm are needed
  • algorithms deal with data that should be hidden from the client

1.9.3. Diagram

Created using PhpStorm and yFiles.

Class diagram of the Strategy pattern

1.9.4. Implementation

ExportInterface.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php

namespace Phpatterns\Behavioral\Strategy;

interface ExportInterface
{
    /**
     * @param string $filePath
     * @return string - path of the exported file
     */
    public function export($filePath);
}

CsvExport.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace Phpatterns\Behavioral\Strategy\Export;

use Phpatterns\Behavioral\Strategy;

class CsvExport implements Strategy\ExportInterface
{
    /**
     * @param string $filePath
     * @return string - path of the exported file
     */
    public function export($filePath)
    {
        // ...
        // Do the necessary to export the file to CSV format
        // ..

        return 'newFile.csv';
    }
}

PdfExport.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace Phpatterns\Behavioral\Strategy\Export;

use Phpatterns\Behavioral\Strategy;

class PdfExport implements Strategy\ExportInterface
{
    /**
     * @param string $filePath
     * @return string - path of the exported file
     */
    public function export($filePath)
    {
        // ...
        // Do the necessary to export the file to PDF format
        // ..

        return 'newFile.pdf';
    }
}

File.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

namespace Phpatterns\Behavioral\Strategy;

class File
{
    /** @var string */
    private $path;

    /** @param $path */
    public function __construct($path)
    {
        $this->path = $path;
    }

    /**
     * @param ExportInterface $exportStrategy
     * @return string
     */
    public function exportTo(ExportInterface $exportStrategy)
    {
        return $exportStrategy->export($this->path);
    }
}

1.9.5. Tests

StrategyTest.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php

namespace Test\Phpatterns\Behavioral\Strategy;

use Phpatterns\Behavioral\Strategy;
use Phpatterns\Behavioral\Strategy\Export;

class StrategyTest extends \PHPUnit_Framework_TestCase
{
    /** @var Export\CsvExport */
    private $csvStrategy;

    /** @var Export\PdfExport */
    private $pdfStrategy;

    /** @var Strategy\File */
    private $file;

    protected function setUp()
    {
        $this->csvStrategy = new Export\CsvExport();
        $this->pdfStrategy = new Export\PdfExport();

        $this->file = new Strategy\File('test.txt');
    }

    public function testStrategyInstances()
    {
        $this->assertInstanceOf(Strategy\ExportInterface::class, $this->csvStrategy);
        $this->assertInstanceOf(Strategy\ExportInterface::class, $this->pdfStrategy);
    }

    public function testCsvStrategy()
    {
        $this->assertSame(
            'newFile.csv',
            $this->file->exportTo($this->csvStrategy)
        );
    }

    public function testPdfStrategy()
    {
        $this->assertSame(
            'newFile.pdf',
            $this->file->exportTo($this->pdfStrategy)
        );
    }
}