09/01/2019 - PHP
The strategy pattern is used when we need to execute some logic based on information provided at runtime. It is technically same as conditional statements such as if..else
, select .. case
so on. but OOP style. It is a great example for SOLID's the Open/Closed Principle. There can be a few ways of using this pattern but I'll just touch up on the most common variations.
class MessagePublisher
{
private $strategy;
public function __construct(StrategyInterface $strategy)
{
$this->strategy = $strategy;
}
public function publish(string $message): string
{
return $this->strategy->process($message);
}
}
interface StrategyInterface
{
public function process(string $message): string;
}
class FacebookStrategy implements StrategyInterface
{
public function process(string $message): string
{
return sprintf('Message "%s" published on Facebook.', $message);
}
}
class TwitterStrategy implements StrategyInterface
{
public function process(string $message): string
{
return sprintf('Message "%s" published on Twitter.', $message);
}
}
require_once 'MessagePublisher.php';
$messagePublisher = new MessagePublisher(new FacebookStrategy());
echo $messagePublisher->publish('Hello');
echo PHP_EOL;
$messagePublisher = new MessagePublisher(new TwitterStrategy());
echo $messagePublisher->publish('Hello');
echo PHP_EOL;
$ php oop/MessagePublisher/index.php
Message "Hello" published on Facebook.
Message "Hello" published on Twitter.
class HomePainter
{
private $painters;
public function __construct(array $painters)
{
$this->painters = $painters;
}
public function start(Home $home, string $section): ?string
{
/** @var StrategyInterface $painter */
foreach ($this->painters as $painter) {
if ($painter->canPaint($section)) {
return $painter->paint($home);
}
}
return null;
}
}
class Home
{
public function doors(): string
{
return 'Doors painted yellow';
}
public function steps(): string
{
return 'Steps painted blue';
}
}
interface StrategyInterface
{
public function canPaint(string $section): bool;
public function paint(Home $home): string;
}
class YellowPainterStrategy implements StrategyInterface
{
public function canPaint(string $section): bool
{
return 'doors' === $section;
}
public function paint(Home $home): string
{
return $home->doors();
}
}
class BluePainterStrategy implements StrategyInterface
{
public function canPaint(string $section): bool
{
return 'steps' === $section;
}
public function paint(Home $home): string
{
return $home->steps();
}
}
require_once 'HomePainter.php';
$home = new Home();
$homePainter = new HomePainter([
new YellowPainterStrategy(),
new BluePainterStrategy(),
]);
echo $homePainter->start($home, 'doors');
echo PHP_EOL;
echo $homePainter->start($home, 'steps');
echo PHP_EOL;
$ php oop/HomePainter/index.php
Doors painted yellow
Steps painted blue
class NumberProcessor
{
private $strategies;
public function addProcessor(StrategyInterface $strategy)
{
$this->strategies[] = $strategy;
return $this;
}
public function run(int $number): int
{
/** @var StrategyInterface $strategy */
foreach ($this->strategies as $strategy) {
$number = $strategy->process($number);
}
return $number;
}
}
interface StrategyInterface
{
public function process(int $number): int;
}
class SumStrategy implements StrategyInterface
{
public function process(int $number): int
{
return $number + $number;
}
}
class MultiplyStrategy implements StrategyInterface
{
public function process(int $number): int
{
return $number * $number;
}
}
require_once 'NumberProcessor.php';
$numberProcessor = new NumberProcessor();
$numberProcessor
->addProcessor(new SumStrategy())
->addProcessor(new MultiplyStrategy());
echo $numberProcessor->run(4);
echo PHP_EOL;
$ php oop/NumberProcessor/index.php
64