Design Patterns — 3. Behavioral Design Pattern
By: Ercan Çavuşoğlu
Tags: Design Patterns

Behavioral Design Pattern

<?php



namespace Behavioral\ChainOfResponsibility;



class Expense

{

public $detail;

public $amount;

}



abstract class ExpenseHandlerBase

{

/**@var ExpenseHandlerBase */

protected $successor;



abstract public function handleExpense(Expense $expense);



/**

* @param mixed $successor

* @return ExpenseHandlerBase

*/

public function setSuccessor($successor)

{

$this->successor = $successor;

return $this;

}

}



class Manager extends ExpenseHandlerBase

{

public function handleExpense(Expense $expense)

{

if ($expense->amount <= 100) {

echo "manager onayladı";

} elseif ($this->successor !== null) {

$this->successor->handleExpense($expense);

}

}

}



class VicePresident extends ExpenseHandlerBase

{

public function handleExpense(Expense $expense)

{

if ($expense->amount > 100 && $expense->amount <= 1000) {

echo "başkan yardımcısı onayladı";

} elseif ($this->successor !== null) {

$this->successor->handleExpense($expense);

}

}

}



class President extends ExpenseHandlerBase

{

public function handleExpense(Expense $expense)

{

if ($expense->amount > 1000) {

echo "başkan onayladı";

}

}

}



class Program

{

public function run()

{

$manager = new Manager();

$vicePresident = new VicePresident();

$president = new President();



$manager->setSuccessor($vicePresident);

$vicePresident->setSuccessor($president);



$expense = new Expense();

$expense->amount = 100;

$expense->detail = "Gezi";



$manager->handleExpense($expense);

}

}



$program = new Program();

$program->run();

Command Design Pattern

<?php



namespace Behavioral\Command;



class StockManager

{

private $_name = "Laptop";

private $_quantity = 10;



public function buy()

{

echo sprintf("Stock : %s, %s bought!", $this->_name, $this->_quantity);

}



public function sell()

{

echo sprintf("Stock : %s, %s sold!", $this->_name, $this->_quantity);

}

}



interface OrderInterface

{

public function execute();

}



class BuyStock implements OrderInterface

{

/**@var StockManager $_stockManager */

private $_stockManager;



public function __construct(StockManager $stockManager)

{

$this->_stockManager = $stockManager;

}



public function execute()

{

$this->_stockManager->buy();

}

}



class SellStock implements OrderInterface

{

private $_stockManager;



public function __construct(StockManager $stockManager)

{

$this->_stockManager = $stockManager;

}



public function execute()

{

$this->_stockManager->sell();

}

}



class StockController

{

/**@var OrderInterface[] */

protected $_orders = [];



public function takeOrder(OrderInterface $order)

{

$this->_orders[] = $order;

}



public function placeOrders()

{

foreach ($this->_orders as $order) {

$order->execute();

}



unset($this->_orders);

}

}





class Program

{

public function run()

{

$stockManager = new StockManager();

$buyStock = new BuyStock($stockManager);

$sellStock = new SellStock($stockManager);



$stockController = new StockController();



$stockController->takeOrder($buyStock);

$stockController->takeOrder($sellStock);

$stockController->takeOrder($buyStock);



$stockController->placeOrders();

}

}



$program = new Program();

$program->run();

Mediator Design Pattern

<?php



# Farklı sistemleri birbiriyle görüştürmek

# Uçaklarla kuleler arasında iletişim gibi

# Burada öğrencilere soru soran öğretmen ve öğrenci ilişkisi var



namespace Behavioral\Mediator;



abstract class CourseMember

{

protected $mediator;



public function __construct(Mediator $mediator)

{

$this->mediator = $mediator;

}

}



class Teacher extends CourseMember

{

public $name;



public function recieveQuestion(string $question, Student $student)

{

echo sprintf("Teacher recieved a question from %s,%s", $student->name, $question);

}



public function sendNewImageUrl(string $url)

{

echo sprintf("Teacher changed slide : %s", $url);

$this->mediator->updateImage($url);

}



public function answerQuestion(string $answer, Student $student)

{

echo sprintf("Teacher answered question %s,%s", $student->name, $answer);

}



}



class Student extends CourseMember

{

public $name;



public function recieveImage(string $url)

{

echo sprintf("%s received image : %s", $url, $this->name);

}



public function receiveAnswer(string $answer)

{

echo sprintf("Student received answer %s", $answer);

}

}



# Karar veren yer

class Mediator

{

/**@var Teacher */

public $teacher;

/**@var Student[] */

public $students;



public function updateImage(string $url)

{

foreach ($this->students as $student) {

$student->recieveImage($url);

}

}



public function sendQuestion(string $question, Student $student)

{

$this->teacher->recieveQuestion($question, $student);

}



public function sendAnswer(string $answer, Student $student)

{

$student->receiveAnswer($answer);

}

}





class Program

{

public function run()

{

$mediator = new Mediator();



$teacher = new Teacher($mediator);

$teacher->name = "Engin";



$mediator->teacher = $teacher;



$student1 = new Student($mediator);

$student1->name = "Derin";





$student2 = new Student($mediator);

$student2->name = "Salih";



$mediator->students = [$student1, $student2];



$teacher->sendNewImageUrl("slide1.jpg");

$teacher->recieveQuestion("is it true?", $student2);

}

}



$program = new Program();

$program->run();

Memento Design Pattern

<?php

/**

* Bir nesne değişikliğe uğratıldıktan sonra istenildiğinde geri getirmek için çıkarılmış

*/



namespace Behavioral\Memento;



class Book

{

public $title;

public $author;

public $isbn;

public $lastEdited;



/**

* @param mixed $title

* @return Book

*/

public function setTitle($title)

{

$this->title = $title;

$this->setLastEdited();

return $this;

}



/**

* @param mixed $author

* @return Book

*/

public function setAuthor($author)

{

$this->author = $author;

$this->setLastEdited();

return $this;

}



/**

* @param mixed $isbn

* @return Book

*/

public function setIsbn($isbn)

{

$this->isbn = $isbn;

$this->setLastEdited();

return $this;

}



public function setLastEdited()

{

$this->lastEdited = new \DateTime();

}



public function createUndo(): BookMemento

{

return new BookMemento(

$this->title,

$this->author,

$this->isbn,

$this->lastEdited

);

}



public function restoreFromUndo(BookMemento $memento)

{

$this->title = $memento->title;

$this->author = $memento->author;

$this->isbn = $memento->isbn;

$this->lastEdited = $memento->lastEdited;

}



public function showBook()

{

return sprintf(

"%s, %s, %s edited %s",

$this->title,

$this->author,

$this->isbn,

$this->lastEdited->format("Y-m-d H:i:s")

);

}





}



class BookMemento

{

public $title;

public $author;

public $isbn;

public $lastEdited;



/**

* BookMemento constructor.

* @param $title

* @param $author

* @param $isbn

* @param $lastEdited

*/

public function __construct($title, $author, $isbn, $lastEdited)

{

$this->title = $title;

$this->author = $author;

$this->isbn = $isbn;

$this->lastEdited = $lastEdited;

}

}



class CareTaker

{

/**@var BookMemento */

public $memento;

}



class Program

{

public function run()

{

$book = new Book();

$book

->setTitle("Sefiller")

->setAuthor("V.Hugo")

->setIsbn("123456");

echo $book->showBook();

echo "

";



$history = new CareTaker();

$history->memento = $book->createUndo();



$book

->setIsbn("1111")

->setAuthor("Victor Hugo");

echo $book->showBook();

echo "

";



$book->restoreFromUndo($history->memento);

echo $book->showBook();

echo "

";



}

}



$program = new Program();

$program->run();



# Output:



# Sefiller, V.Hugo, 123456 edited 2020-12-06 04:31:15

# Sefiller, Victor Hugo, 1111 edited 2020-12-06 04:31:15

# Sefiller, V.Hugo, 123456 edited 2020-12-06 04:31:15

Observer

<?php



namespace Behavioral\Observer;



class ProductManager

{

public $observers = [];



public function updatePrice()

{

echo "Product price changed";

$this->notify();

}



public function attach(AbstractObserver $observer)

{

$this->observers[$observer->id] = $observer;

}



public function detach(AbstractObserver $observer)

{

unset($this->observers[$observer->id]);

}



private function notify()

{

foreach ($this->observers as $observer) {

$observer->update();

}

}

}



abstract class AbstractObserver

{

public $id;



abstract public function update();

}



class CustomerObserver extends AbstractObserver

{

public function update()

{

echo "Msg to customer";

}

}



class EmployeeObserver extends AbstractObserver

{

public function update()

{

echo "Msg to employee";

}

}



class Program

{

public function run()

{

$productManager = new ProductManager();

$employee = new EmployeeObserver();

$employee->id = 1;

$productManager->attach($employee);



$employee2 = new CustomerObserver();

$employee2->id = 2;

$productManager->attach($employee2);



$productManager->detach($employee2);



$productManager->updatePrice();



}

}



$program = new Program();

$program->run();

State

<?php



namespace Behavioral\State;



class ModifiedState implements StateInterface

{

public function doAction(Context $context)

{

echo "State: Modified";

$context->state = $this;

}



public function __toString()

{

return "Modified";

}

}



class DeletedState implements StateInterface

{

public function doAction(Context $context)

{

echo "State: Deleted";

$context->state = $this;

}



public function __toString()

{

return "Deleted";

}

}



class AddedState implements StateInterface

{

public function doAction(Context $context)

{

echo "State: Added";

$context->state = $this;

}



public function __toString()

{

return "Added";

}

}



class Context

{

/**@var StateInterface */

public $state;

}



interface StateInterface

{

public function doAction(Context $context);

}



class Program

{

public function run()

{

$context = new Context();

$modifiedState = new ModifiedState();

$modifiedState->doAction($context);



$deletedState = new DeletedState();

$deletedState->doAction($context);



echo $context->state->__toString()."

";

}

}



$program = new Program();

$program->run();

Strategy

<?php



namespace Behavioral\Strategy;



abstract class CreditCalculatorBase

{

abstract public function calculate();

}



class Before2010Calculator extends CreditCalculatorBase

{

public function calculate()

{

echo "2010 öncesi müşteriler için hesaplandı";

}

}



class After2010Calculator extends CreditCalculatorBase

{

public function calculate()

{

echo "2010 sonrası müşteriler için hesaplandı";

}

}



class CustomerManager

{

/** @var CreditCalculatorBase */

public $creditCalculatorBase;



public function saveCredit()

{

$this->creditCalculatorBase->calculate();

}

}



class Program

{

public function run()

{

$customerManager = new CustomerManager();

$customerManager->creditCalculatorBase = new Before2010Calculator();

$customerManager->saveCredit();



$customerManager2 = new CustomerManager();

$customerManager2->creditCalculatorBase = new After2010Calculator();

$customerManager2->saveCredit();

}

}



$program = new Program();

$program->run();

Template

<?php



namespace Behavioral\Template;



abstract class ScoringAlgorithm

{

abstract public function calculateBaseScore(int $hits);



abstract public function calculateReduction(\DateInterval $time);



abstract public function calculateOverallScore($score, $reduction);



public function generateScore(int $hits, \DateInterval $time)

{

$score = $this->calculateBaseScore($hits); # skor heseplanır



$reduction = $this->calculateReduction($time); # kırılacak puan hesaplanır



return $this->calculateOverallScore($score, $reduction);

}

}



class MensScoringAlgorithm extends ScoringAlgorithm

{

public function calculateBaseScore(int $hits)

{

return $hits * 100;

}



public function calculateReduction(\DateInterval $time)

{

return $time->format('s') / 5;

}



public function calculateOverallScore($score, $reduction)

{

return $score - $reduction;

}

}



class WomansScoringAlgorithm extends ScoringAlgorithm

{

public function calculateBaseScore(int $hits)

{

return $hits * 100;

}



public function calculateReduction(\DateInterval $time)

{

return $time->format('s') / 3;

}



public function calculateOverallScore($score, $reduction)

{

return $score - $reduction;

}

}



class ChildrensScoringAlgorithm extends ScoringAlgorithm

{

public function calculateBaseScore(int $hits)

{

return $hits * 80;

}



public function calculateReduction(\DateInterval $time)

{

return $time->format('s') / 2;

}



public function calculateOverallScore($score, $reduction)

{

return $score - $reduction;

}

}



class Program

{

public function run()

{

$d1 = new \DateTime("2012-07-08 11:14:15.638276");

$d2 = new \DateTime("2012-07-08 11:14:16.889342");

$timespan = $d2->diff($d1);



$algorithm = new MensScoringAlgorithm();

echo $algorithm->generateScore(8, $timespan);



$womanAlgorithm = new WomansScoringAlgorithm();

echo $womanAlgorithm->generateScore(8, $timespan);



$childrenAlgorithm = new ChildrensScoringAlgorithm();

echo $childrenAlgorithm->generateScore(8, $timespan);

}

}



$program = new Program();

$program->run();

Visitor Design Pattern