techtalk#8: design patterns in real life
DESCRIPTION
A few patterns explained and shown in PHP and Javascript. Enjoy!TRANSCRIPT
Design Patterns
Денис Княжев
Java (Java EE, Swing (desktop), JBoss, Tomcat, Glassfish, Spring, Hibernate, Google App Engine)Javascript (JQuery, JavascriptMVC)Databases (MySQL, PostgreSQL, Cassandra, Google Cloud Datastore)AndroidPHP (half-trainee: Apache, Zend 1x)IOS (trainee)C/C++ (trainee)
AreasHealthcareGISe-commerceSocial NetworkingGaming (sometime...)
Open sourceGithub -> denisk20http://programmer-dvorak.appspot.com/ (Javascript)Bullshit Bingo Champion (Android)Draw Graph (Java desktop)
Developer, open source enthusiast
1. Паттерны придумали умники у которых слишком
много времени?
2. Немного паттернов
a. Template method
b. Command
c. Composite
d. Visitor
3. Q&A
1. Паттерны придумали умники у которых слишком много времени?
1994C++, Smalltalk
Стандартные решения стандартных проблем
Слишком часто используются не к месту
2. Немного паттернов
a. Template method
b. Command
c. Composite
d. Visitor
Template Method (Hollywood principle)Don’t call us, we’ll call you
Challenge: сохранить заметку.
Заметки могут быть разных видов (текстовые, голосовые, фото и т.д.)
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;
protected function saveExtra( DB_Note $dbNote){}
$this->saveExtra($dbNote);
protected function saveExtra(DB_Note $dbNote){ $dbNote->setPhoto($this->photo));}
protected function saveExtra(DB_Note $dbNote){ $dbNote->setVideo($this->video);}
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;
protected abstract function getTag();
$dbNote->setTag($this->getTag());
protected function getTag(){ return "Photo";}
protected function getTag(){ return "Video";}
Template Method: Summary
Позволяет вынести в Parent class очень много логики => эффективный DRY(Do not Repeat Yourself)
Навязывает наследование
Command (Execute something later)
Challenge:
● возможность batch-сохранения изменения в заметках● возможность отмены изменений в заметках
interface Command{ public function execute();}
interface UndoableCommand extends Command{ public function undo();}
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(); }}
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(); }}
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 }}
Command: Summary
● Абстрагирует не данные, а действие
● “Отложенное” выполнение● Batch-запуск● Возможность отмены и т.д.
● Память
Composite: иерархии объектов
Challenge:
● возможность сохранения всего дерева заметок(Заметку, её комментарии, комментарии на комментарии и т.д.)
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(); } }}
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();
Composite: Summary
● Позволяет выполнять операции над всей иерархией объектов
● Поощряет делать много небольших классов вместо нескольких больших
● Вся иерархия хранится в памяти
● Поощряет наследование
Visitor: разные операции над разными объектамиChallenge:
Text notes Photo notes
Render
Share
interface Visitor{ public function visitTextNote(TextNote $note); public function visitPhotoNote(PhotoNote $note);}
interface Note{ public function accept(Visitor $visitor);}
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); }}
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>"; }}
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); }}
$notes = array();$notes[] = new TextNote();$notes[] = new PhotoNote();
Visitor renderVisitor = new RenderVisitor();Visitor shareVisitor = new ShareVisitor($account);
$this->processAllNotes($renderVisitor, $notes); //render all$this->processAllNotes($shareVisitor, $notes); //share all
function processAllTextNotes(Visitor $visitor, array $notes){ foreach($notes as $note) { $note->accept($visitor); //magic (double dispatch) }}
Visitor: Summary
● Полностью разделяет алгоритм и структуру данных
● Выделяет “разные вкусы” одного и того же алгоритма для разных типов данных
● Большой● Страшный● Сложный
Big summary
Использовать pattern не по назначению - большее зло, чем не использовать вообще● Template Method - “don’t call us, we’ll call you”● Command - отложенный запуск● Composite - иерархии объектов● Visitor - разделение алторитма и структуры
данных