I am currently learning about design patterns and I came across strategy pattern. I understood it, but now I want to know what would be the best solution to change strategy at runtime. Is it good solution to use ENV variables? Example:
interface Logger{
public function log();
}
class SomeOtherLogger implements Logger {
public function log(){
echo "Logging to something else";
}
}
class FileLogger implements Logger {
public function log(){
echo "Logging to file";
}
}
class Main{
public function doSomething(Loggers $logger){
$logger->log();
}
}
$main = new main();
$main->doSomething(new FileLogger);
One thing that came across my mind is to use environment variable, but I am not sure what is the best way to do it, this one doesn't seem right to me.
$loggingStrategy = env('LOGGING_TYPE') . 'Logger';
$main = new main();
$main->doSomething(new $loggingStrategy);
If you are using Laravel I have a better solution. I hope it works for you:
Laravel has a Manager base class that you can use to implement a strategy pattern. Consider we want to great users depends on their languages.
First, let's implement our language classes:
namespace App\Welcome;
class English
{
public function great()
{
return 'Hi!';
}
}
and for German:
namespace App\Welcome;
class German
{
public function great()
{
return 'Halo!';
}
}
Now we create Welcome class that extends Laravel Manager base class:
namespace App;
use App\Welcome\English;
use App\Welcome\German;
use Illuminate\Support\Manager;
class Welcome extends Manager
{
public function getDefaultDriver()
{
return 'english';
}
public function createGermanDriver()
{
return new German();
}
public function createEnglishDriver()
{
return new English();
}
}
Now you can you can use strategy pattern and define a default driver for your Welcome class. If you want to change the driver at runtime you can use driver method on the welcome class:
$greater = app(Welcome::class);
return $greater->driver('german')->great();
Although in this way, you use Laravel IOC container too. But if you want to be more convenient, combine this pattern with Laravel Facade feature. For instance, in our example, you should only add Facades prefix to the welcome class use keyword. The final code would be like this:
use Facades\App\Welcome; // <-- Laravel automatically would implement facade on the welcome class
Route::get('/', function () {
return Welcome::driver('german')->great();
});
<?php
namespace App\Http\Controllers\DesignPattern\Strategy;
use App\Traits\ApiResponser;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Strategy\Sorting\SortingStrategyContext;
class StrategyController extends Controller
{
use ApiResponser;
public function sortingTest(Request $request)
{
$items = [5, 3, 2, 4, 1];
$sortingstrategycontext = new SortingStrategyContext('quicksort');
$sortedItems = $sortingstrategycontext->sort($items);
return $this->set_response($sortedItems, 200,'success', ['Sorting!']);
}
}
<?php
namespace App\Strategy\Sorting;
interface SortingStrategy
{
public function sort(array $items): array;
}
<?php
namespace App\Strategy\Sorting;
use App\Strategy\Sorting\SortingStrategy;
use App\Strategy\Sorting\BubbleSortStrategy;
use App\Strategy\Sorting\QuickSortStrategy;
class SortingStrategyContext
{
private SortingStrategy $strategy;
public function __construct( string $sortingStrategy )
{
switch ($sortingStrategy) {
case 'bubblesort':
$this->strategy = new BubbleSortStrategy();
break;
case 'quicksort':
$this->strategy = new QuickSortStrategy();
break;
default:
$this->strategy = new QuickSortStrategy();
break;
}
}
public function sort($items)
{
return $this->strategy->sort($items);
}
}
<?php
namespace App\Strategy\Sorting;
use App\Strategy\Sorting\SortingStrategy;
class BubbleSortStrategy implements SortingStrategy
{
public function sort(array $items): array
{
$count = count($items);
for ($i = 0; $i < $count; $i++) {
for ($j = 0; $j < $count - $i - 1; $j++) {
if ($items[$j] > $items[$j + 1]) {
$temp = $items[$j];
$items[$j] = $items[$j + 1];
$items[$j + 1] = $temp;
}
}
}
return $items;
}
}
<?php
namespace App\Strategy\Sorting;
use App\Strategy\Sorting\SortingStrategy;
class QuickSortStrategy implements SortingStrategy
{
public function sort(array $items): array
{
if (count($items) <= 1) {
return $items;
}
$pivot = array_shift($items);
$left = $right = array();
foreach ($items as $item) {
if ($item < $pivot) {
$left[] = $item;
} else {
$right[] = $item;
}
}
return array_merge($this->sort($left), array($pivot), $this->sort($right));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With