3.11. Strategy

3.11.1. Terminologie:

  • Context

  • Strategy

  • Concrete Strategy

3.11.2. Doel

Om strategieën te scheiden en om snel tussen de strategieën te schakelen. Dit patroon is ook een goed alternatief voor overerving (in plaats van een abstracte klasse die wordt uitgebreid).

3.11.3. Bijvoorbeeld

  • het sorteren van een lijst met objecten, de ene strategie op datum, de andere op id

  • het testen van eenheden vereenvoudigen: bijv. schakelen tussen bestands- en geheugenopslag

3.11.4. UML Diagram

Alt Strategy UML Diagram

3.11.5. Code

Je kan deze broncode terugvinden op GitHub

Context.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\Strategy;
 6
 7class Context
 8{
 9    public function __construct(private Comparator $comparator)
10    {
11    }
12
13    public function executeStrategy(array $elements): array
14    {
15        uasort($elements, [$this->comparator, 'compare']);
16
17        return $elements;
18    }
19}

Comparator.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\Strategy;
 6
 7interface Comparator
 8{
 9    /**
10     * @param mixed $a
11     * @param mixed $b
12     */
13    public function compare($a, $b): int;
14}

DateComparator.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\Strategy;
 6
 7use DateTime;
 8
 9class DateComparator implements Comparator
10{
11    public function compare($a, $b): int
12    {
13        $aDate = new DateTime($a['date']);
14        $bDate = new DateTime($b['date']);
15
16        return $aDate <=> $bDate;
17    }
18}

IdComparator.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\Strategy;
 6
 7class IdComparator implements Comparator
 8{
 9    public function compare($a, $b): int
10    {
11        return $a['id'] <=> $b['id'];
12    }
13}

3.11.6. Test

Tests/StrategyTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\Strategy\Tests;
 6
 7use DesignPatterns\Behavioral\Strategy\Context;
 8use DesignPatterns\Behavioral\Strategy\DateComparator;
 9use DesignPatterns\Behavioral\Strategy\IdComparator;
10use PHPUnit\Framework\TestCase;
11
12class StrategyTest extends TestCase
13{
14    public function provideIntegers()
15    {
16        return [
17            [
18                [['id' => 2], ['id' => 1], ['id' => 3]],
19                ['id' => 1],
20            ],
21            [
22                [['id' => 3], ['id' => 2], ['id' => 1]],
23                ['id' => 1],
24            ],
25        ];
26    }
27
28    public function provideDates()
29    {
30        return [
31            [
32                [['date' => '2014-03-03'], ['date' => '2015-03-02'], ['date' => '2013-03-01']],
33                ['date' => '2013-03-01'],
34            ],
35            [
36                [['date' => '2014-02-03'], ['date' => '2013-02-01'], ['date' => '2015-02-02']],
37                ['date' => '2013-02-01'],
38            ],
39        ];
40    }
41
42    /**
43     * @dataProvider provideIntegers
44     *
45     * @param array $collection
46     * @param array $expected
47     */
48    public function testIdComparator($collection, $expected)
49    {
50        $obj = new Context(new IdComparator());
51        $elements = $obj->executeStrategy($collection);
52
53        $firstElement = array_shift($elements);
54        $this->assertSame($expected, $firstElement);
55    }
56
57    /**
58     * @dataProvider provideDates
59     *
60     * @param array $collection
61     * @param array $expected
62     */
63    public function testDateComparator($collection, $expected)
64    {
65        $obj = new Context(new DateComparator());
66        $elements = $obj->executeStrategy($collection);
67
68        $firstElement = array_shift($elements);
69        $this->assertSame($expected, $firstElement);
70    }
71}