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