4. Patron de conception Décorateur “ En programmation orientée objet, le patron de conception décorateur est un motif qui permet l'ajout dynamique de fonctionnalités à un objet existant.” – Wikipedia, “Décorateur_(patron_de_conception)”
5.
6.
7. interface Window { public function isOpen(); public function open(); public function close (); }
8. class StandardWindow implements Window { protected $_open = false; public function isOpen() { return $this ->_open; } public function open() { if (! $this ->_open) { $this ->_open = true; } } public function close () { if ( $this ->_open) { $this ->_open = false; } } }
9. class LockedWindow implements Window { protected $_window ; public function __construct(Window $window ){ $this ->_window = $window ; $this ->_window-> close (); } public function isOpen() { return false; } public function open() { throw new Exception( 'Cannot open locked windows' ); } public function close () { $this ->_window-> close (); } }
10. class LockedWindow { protected $_window ; public function __construct(Window $window ) { $this ->_window = $window ; $this ->_window-> close (); } public function isOpen() { return false; } public function __call( $method , $args ) { if (! method_exists ( $this ->_window, $method )) { throw new Exception( 'Invalid method' ); } return $this ->_window-> $method (); } }
11. Patron de conception Stratégie “ Un patron de conception particulier, dans lequel les algorithmes peuvent être sélectionnés lors de l'exécution.” – Wikipedia, “Strategy_pattern”
12.
13. class Window { public $strategy ; public function open() { $this -> $strategy ->open(); } } interface OpenStrategy { public function open(); }
14. class RaiseStrategy implements OpenStrategy { public function open() { } } class LeverStrategy implements OpenStrategy { public function open() { } }
33. <label for = "bar[foo]" > Foo </label> <input id = "bar-foo" name = "bar[foo]" type = "text" value = "test" />
84. class My_Form_Element_Date extends Zend_Form_Element_Xhtml { // ... public function loadDefaultDecorators() { if ( $this ->loadDefaultDecoratorsIsDisabled()) { return ; } if (empty( $decorators = $this ->getDecorators() )) { $this ->addDecorator( 'Date' ) // ... ; } } // ... }
85. Maintenant on l'utilise ! $d = new My_Form_Element_Date( 'dateOfBirth' ); $d ->setLabel( 'Date of Birth: ' ) ->setView(new Zend_View()); // Ceux-ci sont équivalents : $d ->setValue( '20 April 2009' ); $d ->setValue( array ( 'year' => '2009' , 'month' => '04' , 'day' => '20' ));
86. <dt id = "dateOfBirth-label" ><label for = "dateOfBirth" class = "optional" > Date of Birth: </label></dt> <dd id = "dateOfBirth-element" > <input type = "text" name = "dateOfBirth[day]" id = "dateOfBirth-day" value = "20" size = "2" maxlength = "2" > / <input type = "text" name = "dateOfBirth[month]" id = "dateOfBirth-month" value = "4" size = "2" maxlength = "2" > / <input type = "text" name = "dateOfBirth[year]" id = "dateOfBirth-year" value = "2009" size = "4" maxlength = "4" > </dd>
Traditional locked window; implements same interface as decorated object
Duck-typed locked window
UML diagram of strategy pattern. Concrete object allows attaching objects that implement a particular strategy, or interface; it then calls a defined method on the attached object
Calling object and interface for strategy
Implementations of the strategy
Generate simple markup with label and form input
Two ways to use the decorator: (1) attaching the instance (2) setting the plugin path and specifying it by short name
The markup generated
How layering works: * First decorator is passed empty content * First decorator replaces content by rendering a view helper and passing the rendered markup to the next decorator
How layering works: * Second decorator pulls the element description, if any, and renders it using formNote() view helper; then appends it and passes it to the third decorator
How layering works: * Third decorator pulls any validation errors, and, if found, passes them to the formErrors() view helper; this is also appended to the content passed in and passed to the fourth decorator
How layering works: * Fourth decorator wraps all the content with a <dd> tag and passes the aggregate content to the fifth decorator
How layering works: * Fifth decorator generates label using formLabel() view helper, and prepends it to the content; the aggregate is returned
Revised SimpleInput decorator; no label generation
Label decorator; only renders label
Typical approach to handling placement (typically append or prepend; replace would not use this strategy)
Specifying multiple decorators at instantiation
Specifying alternate placement for a specific decorator
Reflecting on the element in order to generate custom markup; renders the label and view helper decorators
Composite markup that might not be achieved otherwise... which leads into the next topic
Use the discrete value segments from the element to populate the form input