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 - разделение алторитма и структуры
данных