Патерны программирования. DesignPatternsphp documentation
Скачать 1.98 Mb.
|
9 use DesignPatterns\Behavioral\Command\Invoker; 10 use DesignPatterns\Behavioral\Command\Receiver; 11 use PHPUnit\Framework\TestCase; 12 13 class UndoableCommandTest extends TestCase 14 { 15 public function testInvocation () 16 { 17 $invoker = new Invoker(); 18 $receiver = new Receiver(); 19 20 $invoker -> setCommand ( new HelloCommand( $receiver )); 21 $invoker -> run (); 22 $this -> assertSame ( 'Hello World' , $receiver -> getOutput ()); 23 (continues on next page) 86 Глава 1. Паттерны DesignPatternsPHP Documentation, Выпуск 1.0 (продолжение с предыдущей страницы) 24 $messageDateCommand = new AddMessageDateCommand( $receiver ); 25 $messageDateCommand -> execute (); 26 27 $invoker -> run (); 28 $this -> assertSame ( "Hello World\nHello World [" date ( 'Y-m-d' ) ']' , $receiver -> ˓→ getOutput ()); 29 30 $messageDateCommand -> undo (); 31 32 $invoker -> run (); 33 $this -> assertSame ( "Hello World\nHello World [" date ( 'Y-m-d' ) "]\nHello World ˓→ " , $receiver -> getOutput ()); 34 } 35 } 1.3.3 Интепретатор (Interpreter) Назначение Для некоего языка шаблон описывает его грамматику с помощью терминов «Терминальный символ» и «Нетерминальный символ», а также описывает интерпретатор предложений, созданных с помощью данного языка. Примеры • Интерпретатор бинарной (двоичной) логики, в котором каждый тип логической операции опре- делен в своем собственном классе. 1.3. Поведенческие шаблоны проектирования (Behavioral) 87 DesignPatternsPHP Documentation, Выпуск 1.0 Диаграмма UML Код Также вы можете найти этот код на GitHub AbstractExp.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Interpreter; 6 7 abstract class AbstractExp 8 { 9 abstract public function interpret (Context $context ) : bool; 10 } Context.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Interpreter; 6 (continues on next page) 88 Глава 1. Паттерны DesignPatternsPHP Documentation, Выпуск 1.0 (продолжение с предыдущей страницы) 7 use Exception; 8 9 class Context 10 { 11 private array $poolVariable ; 12 13 public function lookUp (string $name ) : bool 14 { 15 if ( ! key_exists ( $name , $this -> poolVariable )) { 16 throw new Exception( "no exist variable: $name " ); 17 } 18 19 return $this -> poolVariable [ $name ]; 20 } 21 22 public function assign (VariableExp $variable , bool $val ) 23 { 24 $this -> poolVariable [ $variable -> getName ()] = $val ; 25 } 26 } VariableExp.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Interpreter; 6 7 /** 8 * This TerminalExpression 9 */ 10 class VariableExp extends AbstractExp 11 { 12 public function __construct ( private string $name ) 13 { 14 } 15 16 public function interpret (Context $context ) : bool 17 { 18 return $context -> lookUp ( $this -> name ); 19 } 20 21 public function getName () : string 22 { 23 return $this -> name ; 24 } 25 } AndExp.php 1 (continues on next page) 1.3. Поведенческие шаблоны проектирования (Behavioral) 89 DesignPatternsPHP Documentation, Выпуск 1.0 (продолжение с предыдущей страницы) 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Interpreter; 6 7 /** 8 * This NoTerminalExpression 9 */ 10 class AndExp extends AbstractExp 11 { 12 public function __construct ( private AbstractExp $first , private AbstractExp $second ) 13 { 14 } 15 16 public function interpret (Context $context ) : bool 17 { 18 return $this -> first -> interpret ( $context ) && $this -> second -> interpret ( $context ); 19 } 20 } OrExp.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Interpreter; 6 7 /** 8 * This NoTerminalExpression 9 */ 10 class OrExp extends AbstractExp 11 { 12 public function __construct ( private AbstractExp $first , private AbstractExp $second ) 13 { 14 } 15 16 public function interpret (Context $context ) : bool 17 { 18 return $this -> first -> interpret ( $context ) || $this -> second -> interpret ( $context ); 19 } 20 } 90 Глава 1. Паттерны DesignPatternsPHP Documentation, Выпуск 1.0 Тест Tests/InterpreterTest.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Interpreter\Tests; 6 7 use DesignPatterns\Behavioral\Interpreter\AndExp; 8 use DesignPatterns\Behavioral\Interpreter\Context; 9 use DesignPatterns\Behavioral\Interpreter\OrExp; 10 use DesignPatterns\Behavioral\Interpreter\VariableExp; 11 use PHPUnit\Framework\TestCase; 12 13 class InterpreterTest extends TestCase 14 { 15 private Context $context ; 16 private VariableExp $a ; 17 private VariableExp $b ; 18 private VariableExp $c ; 19 20 public function setUp () : void 21 { 22 $this -> context = new Context(); 23 $this -> a = new VariableExp( 'A' ); 24 $this -> b = new VariableExp( 'B' ); 25 $this -> c = new VariableExp( 'C' ); 26 } 27 28 public function testOr () 29 { 30 $this -> context -> assign ( $this -> a , false ); 31 $this -> context -> assign ( $this -> b , false ); 32 $this -> context -> assign ( $this -> c , true ); 33 34 // A B 35 $exp1 = new OrExp( $this -> a , $this -> b ); 36 $result1 = $exp1 -> interpret ( $this -> context ); 37 38 $this -> assertFalse ( $result1 , 'A B must false' ); 39 40 // $exp1 C 41 $exp2 = new OrExp( $exp1 , $this -> c ); 42 $result2 = $exp2 -> interpret ( $this -> context ); 43 44 $this -> assertTrue ( $result2 , '(A B) C must true' ); 45 } 46 47 public function testAnd () 48 { 49 $this -> context -> assign ( $this -> a , true ); (continues on next page) 1.3. Поведенческие шаблоны проектирования (Behavioral) 91 DesignPatternsPHP Documentation, Выпуск 1.0 (продолжение с предыдущей страницы) 50 $this -> context -> assign ( $this -> b , true ); 51 $this -> context -> assign ( $this -> c , false ); 52 53 // A B 54 $exp1 = new AndExp( $this -> a , $this -> b ); 55 $result1 = $exp1 -> interpret ( $this -> context ); 56 57 $this -> assertTrue ( $result1 , 'A B must true' ); 58 59 // $exp1 C 60 $exp2 = new AndExp( $exp1 , $this -> c ); 61 $result2 = $exp2 -> interpret ( $this -> context ); 62 63 $this -> assertFalse ( $result2 , '(A B) C must false' ); 64 } 65 } 1.3.4 Итератор (Iterator) Назначение Добавить коллекции объектов функционал последовательного доступа к содержащимся в ней экзем- плярам объектов без реализации этого функционала в самой коллекции. Примеры • построчный перебор файла, который представлен в виде объекта, содержащего строки, тоже являющиеся объектами. Обработчик будет запущен поверх всех объектов. Примечание Стандартная библиотека PHP SPL определяет интерфейс Iterator, который хорошо подходит для дан- ных целей. Также вам может понадобиться реализовать интерфейс Countable, чтобы разрешить вы- зывать count($object) в вашем листаемом объекте. 92 Глава 1. Паттерны DesignPatternsPHP Documentation, Выпуск 1.0 Диаграмма UML Код Также вы можете найти этот код на GitHub Book.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Iterator; 6 7 class Book 8 { 9 public function __construct ( private string $title , private string $author ) 10 { 11 } 12 13 public function getAuthor () : string 14 { 15 return $this -> author ; 16 } 17 18 public function getTitle () : string (continues on next page) 1.3. Поведенческие шаблоны проектирования (Behavioral) 93 DesignPatternsPHP Documentation, Выпуск 1.0 (продолжение с предыдущей страницы) 19 { 20 return $this -> title ; 21 } 22 23 public function getAuthorAndTitle () : string 24 { 25 return $this -> getTitle () ' by ' $this -> getAuthor (); 26 } 27 } BookList.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Iterator; 6 7 use Countable; 8 use Iterator; 9 10 class BookList implements Countable, Iterator 11 { 12 /** 13 * @var Book[] 14 */ 15 private array $books = []; 16 private int $currentIndex = 0 ; 17 18 public function addBook (Book $book ) 19 { 20 $this -> books [] = $book ; 21 } 22 23 public function removeBook (Book $bookToRemove ) 24 { 25 foreach ( $this -> books as $key => $book ) { 26 if ( $book -> getAuthorAndTitle () === $bookToRemove -> getAuthorAndTitle ()) { 27 unset ( $this -> books [ $key ]); 28 } 29 } 30 31 $this -> books = array_values ( $this -> books ); 32 } 33 34 public function count () : int 35 { 36 return count ( $this -> books ); 37 } 38 39 public function current () : Book 40 { (continues on next page) 94 Глава 1. Паттерны DesignPatternsPHP Documentation, Выпуск 1.0 (продолжение с предыдущей страницы) 41 return $this -> books [ $this -> currentIndex ]; 42 } 43 44 public function key () : int 45 { 46 return $this -> currentIndex ; 47 } 48 49 public function next () 50 { 51 $this -> currentIndex ++ ; 52 } 53 54 public function rewind () 55 { 56 $this -> currentIndex = 0 ; 57 } 58 59 public function valid () : bool 60 { 61 return isset ( $this -> books [ $this -> currentIndex ]); 62 } 63 } Тест Tests/IteratorTest.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Iterator\Tests; 6 7 use DesignPatterns\Behavioral\Iterator\Book; 8 use DesignPatterns\Behavioral\Iterator\BookList; 9 use PHPUnit\Framework\TestCase; 10 11 class IteratorTest extends TestCase 12 { 13 public function testCanIterateOverBookList () 14 { 15 $bookList = new BookList(); 16 $bookList -> addBook ( new Book( 'Learning PHP Design Patterns' , 'William Sanders' )); 17 $bookList -> addBook ( new Book( 'Professional Php Design Patterns' , 'Aaron Saray' )); 18 $bookList -> addBook ( new Book( 'Clean Code' , 'Robert C. Martin' )); 19 20 $books = []; 21 22 foreach ( $bookList as $book ) { 23 $books [] = $book -> getAuthorAndTitle (); (continues on next page) 1.3. Поведенческие шаблоны проектирования (Behavioral) 95 DesignPatternsPHP Documentation, Выпуск 1.0 (продолжение с предыдущей страницы) 24 } 25 26 $this -> assertSame ( 27 [ 28 'Learning PHP Design Patterns by William Sanders' , 29 'Professional Php Design Patterns by Aaron Saray' , 30 'Clean Code by Robert C. Martin' , 31 ], 32 $books 33 ); 34 } 35 36 public function testCanIterateOverBookListAfterRemovingBook () 37 { 38 $book = new Book( 'Clean Code' , 'Robert C. Martin' ); 39 $book2 = new Book( 'Professional Php Design Patterns' , 'Aaron Saray' ); 40 41 $bookList = new BookList(); 42 $bookList -> addBook ( $book ); 43 $bookList -> addBook ( $book2 ); 44 $bookList -> removeBook ( $book ); 45 46 $books = []; 47 foreach ( $bookList as $book ) { 48 $books [] = $book -> getAuthorAndTitle (); 49 } 50 51 $this -> assertSame ( 52 [ 'Professional Php Design Patterns by Aaron Saray' ], 53 $books 54 ); 55 } 56 57 public function testCanAddBookToList () 58 { 59 $book = new Book( 'Clean Code' , 'Robert C. Martin' ); 60 61 $bookList = new BookList(); 62 $bookList -> addBook ( $book ); 63 64 $this -> assertCount ( 1 , $bookList ); 65 } 66 67 public function testCanRemoveBookFromList () 68 { 69 $book = new Book( 'Clean Code' , 'Robert C. Martin' ); 70 71 $bookList = new BookList(); 72 $bookList -> addBook ( $book ); 73 $bookList -> removeBook ( $book ); 74 75 $this -> assertCount ( 0 , $bookList ); (continues on next page) 96 Глава 1. Паттерны DesignPatternsPHP Documentation, Выпуск 1.0 (продолжение с предыдущей страницы) 76 } 77 } 1.3.5 Посредник (Mediator) Назначение Этот паттерн позволяет снизить связность множества компонентов, работающих совместно. Объектам больше нет нужды вызывать друг друга напрямую. Это хорошая альтернатива Наблюдателю, если у вас есть “центр интеллекта” вроде контроллера (но не в смысле MVC) Все компоненты (называемые «Коллеги») объединяются в интерфейс Mediator и это хорошо, потому что в рамках ООП, «старый друг лучше новых двух». 1.3. Поведенческие шаблоны проектирования (Behavioral) 97 DesignPatternsPHP Documentation, Выпуск 1.0 Диаграмма UML 98 Глава 1. Паттерны DesignPatternsPHP Documentation, Выпуск 1.0 Код Вы можете найти этот код на GitHub Mediator.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Mediator; 6 7 interface Mediator 8 { 9 public function getUser (string $username ) : string; 10 } Colleague.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Mediator; 6 7 abstract class Colleague 8 { 9 protected Mediator $mediator ; 10 11 final public function setMediator (Mediator $mediator ) 12 { 13 $this -> mediator = $mediator ; 14 } 15 } Ui.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Mediator; 6 7 class Ui extends Colleague 8 { 9 public function outputUserInfo (string $username ) 10 { 11 echo $this -> mediator -> getUser ( $username ); 12 } 13 } UserRepository.php 1.3. Поведенческие шаблоны проектирования (Behavioral) 99 DesignPatternsPHP Documentation, Выпуск 1.0 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Mediator; 6 7 class UserRepository extends Colleague 8 { 9 public function getUserName (string $user ) : string 10 { 11 return 'User: ' $user ; 12 } 13 } UserRepositoryUiMediator.php 1 2 3 declare (strict_types = 1 ); 4 5 namespace DesignPatterns\Behavioral\Mediator; 6 7 class UserRepositoryUiMediator implements Mediator 8 { 9 public function __construct ( private UserRepository $userRepository , private Ui $ui ) 10 { 11 $this -> userRepository -> setMediator ( $this ); 12 $this -> ui -> setMediator ( $this ); 13 } 14 15 public function printInfoAbout (string |