8. Template Method (Hollywood principle)
Don’t call us, we’ll call you
Challenge: сохранить заметку.
Заметки могут быть разных видов (текстовые, голосовые,
фото и т.д.)
9. class TextNote
{
private $date;
private $text;
public function save()
{
class PhotoNote extends TextNote
{
private $photo;
$dbNote = new DB_Note();
$dbNote->setDate($this->date);
$dbNote->setText($this->text);
$dbNote->save();
}
protected function saveExtra(DB_Note
class VideoNote extends TextNote
{
private $video;
$this->saveExtra($dbNote);
protected function saveExtra(
DB_Note $dbNote){}
$dbNote)
{
$dbNote->setPhoto($this->photo));
}
protected function saveExtra(DB_Note
$dbNote)
{
$dbNote->setVideo($this->video);
}
10. class TextNote
{
private $date;
private $text;
public function save()
{
$dbNote = new DB_Note();
$dbNote->setDate($this->date);
$dbNote->setText($this->text);
$dbNote->save();
}
class PhotoNote extends TextNote
{
private $photo;
class VideoNote extends TextNote
{
private $video;
$dbNote->setTag($this->getTag());
protected abstract function getTag();
protected function getTag()
{
return "Photo";
}
protected function getTag()
{
return "Video";
}
11.
12. Template Method: Summary
Позволяет вынести в
Parent class очень
много логики =>
эффективный DRY
(Do not Repeat Yourself)
Навязывает наследование
13. Command (Execute something later)
Challenge:
● возможность batch-сохранения изменения в заметках
● возможность отмены изменений в заметках
14. interface Command
{
public function execute();
}
interface UndoableCommand extends Command
{
public function undo();
}
15. class EditTextCommand implements Command
{
private $note;
private $oldText;
private $newText;
public function execute()
{
if(strcmp($this->note->text,
$this->newText) === 0)
{
return;
}
$this->oldText = $this->note->text;
$this->note->text = $this->newText;
$this->note->save();
}
$commands = array();
$commands[] = $command1;
$commands[] = $command2;
$commands[] = $command3;
//...
public function executeAll()
{
foreach($commands as
$command)
{
$command->execute();
}
}
16. class UndoableEditTextCommand
extends EditCommand
implements UndoableCommand
{
public function undo()
{
if(strcmp($this->note->text,
$this->oldText) === 0)
{
return;
}
$this->newText = $this->note->text;
$this->note->text = $this->oldText;
$this->note->save();
}
}
$commands = array();
$commands[] = $command1;
$commands[] = $command2;
$commands[] = $command3;
//...
public function undoAll()
{
foreach($commands as
$command)
{
$command->undo();
}
}
17. In Javascript the life is easier
Все функции - команды
vag command = function(param1, param2) {...};
command.call(this, “hello”, “world”);
Манипулировать функциями - естественно
function doSomething(value1, value2, comparator) {
if(comparator.call(this, value1, value2) > 0) {
//do something
} else {
//do something else
}
}
18.
19. Command: Summary
● Абстрагирует не данные, а
действие
● “Отложенное” выполнение
● Batch-запуск
● Возможность отмены и т.д.
● Память
20. Composite: иерархии объектов
Challenge:
● возможность сохранения всего дерева заметок
(Заметку, её комментарии, комментарии на
комментарии и т.д.)
21.
22. interface Note
{
public function save();
}
abstract class AbstractNote implements
Note
{
private $childNotes = array();
public function addChild(Note $note)
{
$this->childNotes[] = $note;
}
private function saveInternal()
{
//saves this note
}
public function save()
{
$this->saveInternal();
foreach($this->childNotes as $child)
{
$child->save();
}
}
}
23. class TextNote extends AbstractNote
{
//...
}
class PhotoNote extends AbstractNote
{
//...
}
class VideoNote extends AbstractNote
{
//...
}
$parent = new VideoNote();
$comment = new TextNote();
$videoResponse = new VideoNote();
$commentOnVideoResponse =
new TextNote();
$videoResponse->addChild(
$commentOnVideoResponse);
$parent->addChild($videoResponse);
$parent->addChild($comment);
$parent->save();
24.
25. Composite: Summary
● Позволяет выполнять
операции над всей
иерархией объектов
● Поощряет делать много
небольших классов вместо
нескольких больших
● Вся иерархия хранится в
памяти
● Поощряет наследование
27. interface Visitor
{
public function visitTextNote(TextNote $note);
public function visitPhotoNote(PhotoNote $note);
}
interface Note
{
public function accept(Visitor $visitor);
}
28. class TextNote implements Note
{
private $text;
//...
public function accept(Visitor $visitor)
{
$visitor->visitTextNote($this);
}
}
class PhotoNote implements Note
{
private $photo;
//...
public function accept(Visitor $visitor)
{
$visitor->visitPhotoNote($this);
}
}
29. class RenderVisitor implements Visitor
{
public function visitTextNote(TextNote $note)
{
echo "<p>{$note->getText()}</p>";
}
public function visitPhotoNote(PhotoNote $note)
{
echo "<img src='{$note->getPhoto()->src}'></img>";
}
}
30. class ShareVisitor implements Visitor
{
private $account;
//...
public function visitTextNote(TextNote $note)
{
$account->shareText($note->getText());
}
public function visitPhotoNote(PhotoNote $note)
{
$image = $note->getImage();
$image = self::resizeImage($image);
$account->shareImage($image);
}
}
31. $notes = array();
$notes[] = new TextNote();
$notes[] = new PhotoNote();
Visitor renderVisitor = new RenderVisitor();
Visitor shareVisitor = new ShareVisitor($account);
function processAllTextNotes(Visitor $visitor, array $notes)
{
foreach($notes as $note)
{
$note->accept($visitor); //magic (double dispatch)
}
}
$this->processAllNotes($renderVisitor, $notes); //render all
$this->processAllNotes($shareVisitor, $notes); //share all
32.
33. Visitor: Summary
● Полностью разделяет
алгоритм и структуру
данных
● Выделяет “разные вкусы”
одного и того же алгоритма
для разных типов данных
● Большой
● Страшный
● Сложный
34. Big summary
Использовать pattern не по назначению -
большее зло, чем не использовать вообще
● Template Method - “don’t call us, we’ll call you”
● Command - отложенный запуск
● Composite - иерархии объектов
● Visitor - разделение алторитма и структуры
данных