You are on page 1of 144

Design Patterns Bootcamp

Ralph Schindler, Matthew Weier O'Phinney, and Enrico Zimuel ZendCon 2012

What are Design Patterns?

A formal way of documenting a solution to a design problem in a particular field of expertise. (http://en.wikipedia.org /wiki/Design_patterns)

Elements of design patterns


1. Describe the problem 2. Describe the solution 3. Describe when it is applicable

A Grammar for Software Development

What design patterns are not


Copy and paste solutions Standard implementation

What we'll cover today


Foundation patterns Behavioral patterns Modeling patterns

Our presentation pattern


Outline the problem Name the pattern Describe how the pattern implementation resolves the problem

Foundation patterns

Patterns we'll cover


Bridge Facade Proxy Iterator Visitor Decorator

Bridge
Problem: manage an abstraction with different implementations First solution: use inheritance to build different implementations Cons: the implementations are too close with the abstraction. The abstraction and implementations cannot be independently extended or composed. Better solution: use the Bridge pattern

Bridge: UML diagram

Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface DrawingAPI { public function drawCircle($x, $y, $radius); } class DrawingAPI1 implements DrawingAPI { public function drawCircle($x, $y, $radius) { printf ("API1 draw (%d, %d, %d)\n", $x, $y, $radius); }

class DrawingAPI2 implements DrawingAPI { public function drawCircle($x, $y, $radius) { printf ("API2 draw (%d, %d, %d)\n", $x, $y, $radius); }

Implementation (2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 abstract class Shape { protected $api; protected $x; protected $y; public function __construct(DrawingAPI $api) { $this->api = $api; } } class CircleShape extends Shape { protected $radius; public function __construct($x, $y, $radius, DrawingAPI $api) { parent::__construct($api); $this->x = $x; $this->y = $y; $this->radius = $radius; } public function draw() { $this->api->drawCircle($this->x, $this->y, $this->radius); } }

Usage example
1 2 3 4 5 6 7 8 9 10 11 12 $shapes = array( new CircleShape(1, 3, 7, new DrawingAPI1()), new CircleShape(5, 7, 11, new DrawingAPI2()), ); foreach ($shapes as $sh) { $sh->draw(); } // Expected output: // API1 draw (1, 3, 7) // API2 draw (5, 7, 11)

Facade
Problem: simplify the usage of a complex code Solution: use the Facade pattern, a simplified interface to a larger body of code, such as a class library. Using a facade schema we can hide all the logic of the complex code, while the mechanism in question knows nothing about the calling class.

Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class CPU { public function freeze() { echo "Freeze the CPU\n"; } public function jump($address) { echo "Jump to $address\n"; } public function execute() { echo "Execute\n"; } } class Memory { public function load($address, $data) { echo "Loading address $address with data: $data\n"; } } class Disk { public function read($sector, $size) { return "data from sector $sector ($size)"; } }

Implementation (2)
1 class Computer { 2 const BOOT_ADDRESS = 0; 3 const BOOT_SECTOR = 1; const SECTOR_SIZE = 16; 4 5 protected $cpu; 6 protected $mem; protected $hd; 7 8 public function __construct(CPU $cpu, Memory $mem, Disk $hd) { $this->cpu = $cpu; 9 $this->mem = $mem; 10 $this->hd = $hd; 11 12 } public function startComputer() { 13 $this->cpu->freeze(); 14 $this->mem->load( 15 16 self::BOOT_ADDRESS, $this->hd->read(self::BOOT_SECTOR, self::SECTOR_SIZE)); 17 $this->cpu->jump(self::BOOT_ADDRESS); 18 $this->cpu->execute(); 19 20 } 21 }

Proxy
Problem 1: manage "expensive to create" objects, lazy-loading them only on first access Problem 2: provide a local object representation of remote system processes Problem 3: consuming and controlling access to another object Solution: Design a proxy class that access/extend the object, overriding one or more methods

Proxy: UML diagram

Implementation (Prob. 1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 interface ImageInterface { public function display(); } class Image implements ImageInterface { protected $filename; public function __construct($filename) { $this->filename = $filename; $this->loadFromDisk(); } protected function loadFromDisk() { echo "Loading {$this->filename}\n"; } public function display() { echo "Display {$this->filename}\n"; } }

Implementation (Prob. 1)
1 class ProxyImage implements ImageInterface 2 { protected $id; 3 protected $image; 4 5 public function __construct($filename) { $this->filename = $filename; 6 7 } public function display() { 8 9 if (null === $this->image) { $this->image = new Image($this->filename); 10 11 } return $this->image->display(); 12 13 } 14 }

Usage example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $filename = 'test.png'; $image1 = new Image($filename); // loading necessary echo $image1->display(); // loading unnecessary $image2 = new ProxyImage($filename); // loading unnecessary echo $image2->display(); // loading necessary echo $image2->display(); // loading unnecessary // // // // // // Expected output: Loading test.png Display test.png Loading test.png Display test.png Display test.png

Implementation (Prob. 3)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class SomeObject { protected $message; public function __construct($message) { $this->message = $message; } protected function doSomething() { return $this->message; } } class Proxy extends SomeObject { protected $proxied; public function __construct(SomeObject $o) { $this->proxied = $o; } public function doSomething() { return ucwords( $this->proxied->doSomething() ); } }

Usage example
1 2 3 4 5 6 7 8 9 $o = new SomeObject('foo bar'); $p = new Proxy($o); printf( "Message from Proxy: %s\n", $p->doSomething() ); // Expected output: // Message from Proxy: Foo Bar

Iterator
Problem: manipulate/traverse a collection of objects with a standard interface Solution: use the Iterator pattern that enables to traverse a container of objects PHP: PHP supports a standard Iterator interface (and Iterators classes in the SPL ready to be used)

PHP Iterator interface


1 2 3 4 5 6 7 8 9 10 interface Traversable { } interface Iterator extends Traversable { public function current(); public function key(); public function next(); public function rewind(); public function valid(); }

Implementation
1 class Fibonacci implements Iterator { 2 protected $value = 0; 3 protected $sum = 0; protected $key = 0; 4 5 public function rewind() { $this->value = 0; 6 $this->key = 0; 7 8 } public function current() { 9 return $this->value; 10 11 } public function key() { 12 return $this->key; 13 14 } 15 ...

Implementation (2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 } ... public function next() { if ($this->value === 0) { $this->value = 1; } else { $old = $this->value; $this->value += $this->sum; $this->sum = $old; } $this->key++; } public function valid() { return ($this->value < PHP_INT_MAX); }

Usage example
1 2 3 4 5 6 7 8 9 10 11 // print the Fibonacci numbers until PHP_INT_MAX foreach ($test = new Fibonacci() as $key => $value) { printf("%d) %d\n", $key, $value); } // print the first 10 Fibonacci's numbers $num = new Fibonacci(); for ($i = 0; $i < 10; $i++) { printf("%d) %d\n", $i, $num->current()); $num->next(); }

Visitor
Problem: separate an algorithm from an object structure on which it operates Solution: uses the Visitor pattern that allows one to add new virtual functions to a family of classes without modifying the classes themselves

Visitor: UML diagram

Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface Visited { public function accept(Visitor $visitor); } class VisitedArray implements Visited { protected $elements = array(); public function addElement($element){ $this->elements[]=$element; } public function getSize(){ return count($this->elements); } public function accept(Visitor $visitor){ $visitor->visit($this); } }

Implementation (2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 interface Visitor { public function visit(VisitedArray $elements); } class DataVisitor implements Visitor { protected $info; public function visit(VisitedArray $visitedArray){ $this->info = sprintf ("The array has %d elements", $visitedArray->getSize()); } public function getInfo(){ return $this->info; } }

Usage example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $visitedArray = new VisitedArray(); $visitedArray->addElement('Element 1'); $visitedArray->addElement('Element 2'); $visitedArray->addElement('Element 3'); $dataVisitor = new DataVisitor(); $visitedArray->accept($dataVisitor); $dataVisitor->visit($visitedArray); printf( "Info from visitor object: %s\n", $dataVisitor->getInfo() );

Decorator
Problem: add functionalities to an existing object dynamically, without extend it Solution: use the Decorator pattern to alter or decorate portions of an existing objects content or functionality without modifying the structure of the original object.

Decorator: UML diagram

Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 interface HtmlElement { public function __toString(); public function getName(); } class InputText implements HtmlElement { protected $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } public function __toString() { return "<input type=\"text\" " . "id=\"{$this->name}\"" . "name=\"{$this->name}\" />\n"; } }

Implementation (2)
1 abstract class HtmlDecorator implements HtmlElement 2 { protected $element; 3 public function __construct(HtmlElement $input) { 4 $this->element = $input; 5 6 } public function getName() { 7 8 return $this->element->getName(); 9 } public function __toString() { 10 11 return $this->element->__toString(); 12 } 13 }

Implementation (3)
1 class LabelDecorator extends HtmlDecorator { 2 protected $label; 3 public function setLabel($label) { $this->label = $label; 4 5 } public function __toString() { 6 $name = $this->getName(); 7 8 return "<label for=\"{$name}\">" 9 . $this->label . "</label>\n" 10 . $this->element->__toString(); 11 } 12 }

Implementation (4)
1 class ErrorDecorator extends HtmlDecorator { 2 protected $error; 3 public function setError($message) { $this->error = $message; 4 5 } public function __toString() { 6 return $this->element->__toString() . 7 8 "<span>{$this->error}</span>\n"; 9 } 10 }

Usage example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // Add a label to the input text $input = new InputText('nickname'); $labelled = new LabelDecorator($input); $labelled->setLabel('Nickname:'); printf("%s\n", $labelled); // Add an error message to the input text $input = new InputText('nickname'); $error = new ErrorDecorator($input); $error->setError('You must enter a unique nickname'); printf("%s\n", $error); // Add a label and an error message to the input text $input = new InputText('nickname'); $labelled = new LabelDecorator($input); $labelled->setLabel('Nickname:'); $error = new ErrorDecorator($labelled); $error->setError('You must enter a unique nickname'); printf("%s\n", $error);

Section 1 Controllers and Workflow

Fundamental Patterns
Strategy/Adapter/Command Factory Subject/Observer

Strategy Adapter Command

Strategy

The problem
You've written code for which you need interchangeable algorithms. Based on the route, you'd handle a request differently. Based on console environment, you might need different line endings. You've got a large switch statement with many cases.

Strategy: UML diagram

Adapter

The problem
You have domain-specific code that you want to use that doesn't follow interfaces of your toolkit/framework. You wrote an XML-RPC server, and now want to route to it. You have a data transfer object that could easily be re-purposed as a request You want to consume another object as a command, but it doesn't follow the interface you've defined.

Adapter: UML diagram

Implementation
Step 1: Extract an interface
1 interface Handler 2 { public function handle(Request $request); 3 4 }

Implementation
Step 2: Compose a strategy
1 class Request 2 { 3 protected $handler; 4 public function setHandler(Handler $handler); public function handle() 5 6 { return $this->handler->handle($this); 7 8 } 9 }

Implementation
Step 3: Class to be adapted
1 class Paste 2 { 3 public function create( $content, $language = 'php' 4 5 ) { 6 // Return array of errors, 7 // or array representing paste 8 } 9 }

Implementation
Extension: Implement the desired interface in an extending object.
1 class PasteAdapter extends Paste implements Handler 2 { public function handle(Request $request) 3 4 { $post = $request->getPost(); 5 $content = $post->get('content', ''); 6 $lang = $post->get('lang', '') 7 8 return $this->create($content, $lang); 9 } 10 }

Implementation
Composition: Implement the desired interface, and inject the object being adapted.
1 class PasteAdapter implements Handler 2 { protected $paste; 3 4 public function setPaste(Paste $paste); public function handle(Request $request) 5 6 { $post = $request->getPost(); 7 $content = $post->get('content', ''); 8 $lang = $post->get('lang', '') 9 10 return $this->paste 11 ->create($content, $lang); 12 } 13 }

Command

The Problem
You have a lot of metadata that needs to be passed to one or more other objects. You discover you're coupling implementation details inside an object that should deal with abstractions. You're passing around query, post, header, and additional collections. You're passing around a set of common objects as individual arguments. The main context object shouldn't need to know what specific objects need to be passed to collaborators.

Command: UML diagram

Implementation
Step 1: Extract a value object
1 interface Request 2 { public function 3 4 public function public function 5 6 public function 7 } getUri(); getQuery(); getPost(); getHeaders();

Implementation
Step 2: Create an interface for strategies/commands
1 interface Handler 2 { public function dispatch(Request $request); 3 4 }

Implementation
Step 3: Write handlers that delegate to other objects
1 2 3 4 5 6 7 8 9 10 11 12 class RoutePath { public function route($path; } class PathHandler implements Handler { protected $routePath; public function dispatch(Request $request) { $uri = $request->getUri(); $path = $uri->getPath(); $this->routePath->route($path); } }

Implementation
Step 4: Compose the strategies/commands
1 class RequestHandler 2 { 3 protected $handlers = array(); 4 protected $request; 5 public function addHandler(Handler $handler); 6 7 public function setRequest(Request $request); 8 public function dispatch() 9 10 { foreach ($this->handlers as $handler) { 11 $handler->dispatch($this->request); 12 13 } 14 } 15 }

Creational Patterns

Factory

The problem
You know that you need an object of a specified type, but the concrete implementation will be determined dynamically. The controller will vary based on request. How pagination occurs will vary based on persistence. Validators will vary based on element.

Factory: UML diagram

Implementation
Step 1: Extract the common interface
1 interface Handler 2 { public function handle(Request $request); 3 4 }

Implementation
Step 1a: Define a standard method for object creation
1 interface Handler 2 { 3 // Usually one of: 4 public function __construct($options); 5 // or: 6 public static function factory($options); 7 }

Implementation
Step 2: Define a factory that returns objects of that interface
1 interface Factory 2 { 3 /** 4 * @return Handler 5 */ 6 public function create($type); 7 }

Implementation
Step 3: Compose and consume a factory to get the concrete implementations
1 class RequestHandler 2 { protected $factory; 3 4 public function setFactory(Factory $factory); 5 public function handle(Request $request) 6 { $type = $this->request->getController(); 7 $handler = $this->factory->create($type); 8 return $handler->handle($request); 9 10 } 11 }

Related Patterns
Inversion of Control Dependency Injection Container Service Locator

Service Locator
1 $services->setFactory('foo', function ($services) { 2 // do some work, and create and return 3 // an object instance 4 return $foo; 5 }); 6 $foo = $services->get('foo');

Dependency Injection Container


1 $object = $dic->get('Some\Classname');

Subject/Observer SignalSlot Event Handler

The Problem
You have an indeterminate number of objects that need notifications of certain state changes. When a transaction happens, notify a CSR, and send a confirmation email. When a commit is made, each of the webhooks must be notified.

The Problem (2)


You need to be able to introduce cross-cutting concerns at specific cut points in your application. You need to log the various workflows of the application. You want to be able to introduce caching at a later date if it's needed.

The Problem (3)


You may need to halt execution or modify the workflow if certain conditions are met, but the conditions are not semantically part of the subject. A controller issues a redirect. A controller determines it cannot handle a request. Or another controller can! Based on the Accept header, we need to use a different renderer.

Subject Observer: UML diagram

SignalSlot: UML diagram

Event Handler: UML diagram

Implementation
Subject/Observer
1 class Subject 2 { 3 protected $observers = array(); public function addObserver(Observer $observer) 4 5 { $this->observers[] = $observer 6 7 } public function execute() 8 9 { foreach ($this->observers as $observer) { 10 $observer->notify($this); 11 12 } 13 } 14 }

Implementation
Subject/Observer (cont)
1 interface Observer 2 { public function notify(Subject $subject); 3 4 }

Implementation
SignalSlot
1 interface Signals 2 { public function connect($signal, $callable); 3 public function emit($signal, $argv = null); 4 5 }

Implementation
SignalSlot (cont)
1 class Foo 2 { 3 protected $signals; public function setSignals(Signals $signals); 4 5 public function bar($baz, $bat) 6 7 { $this->signals->emit('bar', $baz, $bat); 8 9 } 10 }

Implementation
SignalSlot (cont)
1 2 3 4 5 6 7 8 $signals = new SignalSlotManager(); $signals->connect('bar', function ($baz, $bat) { printf('%s:%s', $baz, $bat); }); $foo = new Foo(); $foo->setSignals($signals); $foo->bar('do', 'something');

Implementation
Event Handler
1 2 3 4 5 6 7 8 9 10 11 12 13 interface Event { public function public function public function public function } getName(); getTarget(); setParams(array $params); getParams();

interface Events { public function attach($name, $callback); public function trigger( $name, $target, Event $event ); }

Implementation
Event Handler (cont)
1 class Foo 2 { 3 protected $events; public function setEventHandler(Events $events); 4 5 public function bar($baz, $bat) 6 { $event = new Event(); 7 8 $event->setParams(array( 'baz' => $baz, 9 'bat' => $bat, 10 11 )); $this->events->trigger( 12 'bar', $this, $event); 13 14 } 15 }

Implementation
Event Handler (cont)
1 2 3 4 5 6 7 8 9 10 11 12 13 $events = new EventHandler(); $events->attach('bar', function (Event $e) { $params = $e->getParams(); $class = get_class($e->getTarget()); printf('[%s][%s] %s', $e->getName(), $class, json_encode($params) ); }); $foo = new Foo; $foo->setEvents($events); $foo->bar('do', 'something');

More concepts
Short circuiting If a listener returns a particular response, end early Allow a listener to halt the event loop Response aggregation and introspection Global/Static manager, or per object? Event/signal naming

Summary
We examined patterns around interchangeability of algorithms (Strategy, Adapter, Command). We examined how to dynamically build objects of a specific type based on provided criteria (Factory, Builder, IoC). We examined how to compose objects that we can notify of changes or important stages of the application workflow (Subject/Observer, SignalSlot, Event Handler).

Assignment

Build a dispatcher
Controller will be given via a query string argument. Comma-delimit multiple controllers. Only instantiate the controllers specified. Do not use the fully-qualified class names in the query string. Add a non-Controller handler that executes for every request and which logs the query string argument. Use as many of the discussed patterns as possible.

Modeling patterns

Patterns we'll cover


Prototype Mapper Repository Entity, Value Object, Values (Some others in brief)

Why These Particular Patterns?


Again, a common diction and vocabulary These are taken in part from Domain Driven Design (Eric Evans) Tools to find a suitable level of abstraction

Prototype
Category: Creational Pattern, typically used by code promoting extension Problem: objects that need to generate objects as part of a normal workflow

Prototype
First Solution: let your primary object create (call new) for every new object it must create Cons: When object creation is complex or becomes custom, this workflow then requires overriding and customization of the parent class Better Solution: Use the prototype pattern

Prototype UML Diagram

Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 interface PrototypicalInterface { /* Nothing new required */ public function initialize($values); } class PrototypicalFoo implements PrototypicalInterface { public function __construct() {} } class PrototypicalBar implements PrototypicalInterface { public function __construct(\mysqli $mysqli) {} }

Implementation (2)
1 class PrototypeConsumer { 2 protected $p; 3 public function __construct( 4 PrototypicalInterface $p 5 ) { $this->p = $p; 6 7 } public function operation() { 8 $p = clone $this->p; 9 $p->initialize($this->values); 10 return $p; // new instance, 11 12 // based off the foo 13 } 14 }

Usage
1 $pf = new PrototypicalFoo; 2 $pc = new PrototypeConsumer(); 3 $p = $pc->operation(); // a clone $pf, specialized 4 // by the $pc during 5 // operation()

Story: How did I decide to use this once?


Zend Framework's ResultSet object for Zend\Db Goals: Provide a ResultSet interface Allow consumers to build their own specialized ResultSet object Will create a ResultSet per call to query(), execute() on a Stmt.

Found Inside ZF 1.x


1 // inside Zend_Db_Table::find 2 return new $rowsetClass(array( 'table' => $this, 3 'rowClass' => $this->getRowClass(), 4 5 'stored' => true 6 ));

Found Inside ZF 2.x


1 2 3 4 5 6 // inside Zend\Db\TableGateway\AbstractTableGatway::select $result = $statement->execute(); // build result set $resultSet = clone $this->resultSetPrototype; $resultSet->initialize($result);

Usage
All I care is that you implement ResultSetInterface
1 $table = new TableGatgeway( 'my_table', 2 $adapter, 3 4 null, // features 5 new HydratingResultSet(new MyTableHydrator) 6 );

Mapper / Data Mapper


Category: Base Pattern / Data Access Pattern Problem: Need to change an object/array/data into an object (and visa-versa) between two systems that you want to keep their API's separate and code ignorant of each other.

Mapper
First Solution: There are many: cast to stdClass, allow entity object to sort out a translation, use data source specific solution (PDO::FETCH_CLASS for example). Cons: Mixed levels of separation of concerns, repeated code (in the case of translations), etc. Better Solution: Use a Mapper object.

Mapper UML Diagram

Implementation
1 class Artist { 2 public $name, $bio; 3 /** @var Album[] */ 4 public $albums = array(); 5 public function getName() { 6 7 return $this->name; 8 } // ... 9 10 }

Implementation
1 class ArtistMapper { 2 public function mapArrayToArtist( 3 array $data, Artist $artist = null 4 ) { 5 $artist = ($artist) ?: new Artist; $artist->firstName = $data['first_name']; 6 $artist->lastName = $data['last_name']; 7 8 $album = new Album; 9 $album->title = $data['album_1_title']; 10 $artist->albums[] = $album; 11 12 return $artist; 13 } 14 }

Implementation (2)
1 public function mapArtistToArray( 2 Artist $artist 3 ) { 4 return array( 'first_name' => $artist->firstName, 5 'last_name' => $artist->lastName 6 7 ); 8 }

Usage
1 2 3 4 5 $artistData = $dbMapper; $artistMapper = new ArtistDataMapper; $artist = $artistMapper->mapArrayToArtist( $personArray ); // returns Artist object

Repository
Category: Data Access Problem: You don't want SQL in your controller code. You want to hide the persistence implementation from the Model's API (Persistence Ignorance).

Repository
First Solution: create collection returning methods on your Data Access object. Cons: Public API of the Data Access object becomes confused and overloaded with semi-related methods Better Solution: Use the repository pattern

Sidetrack: Persistence Ignorance & Interfaces


"Persistence Ignorance" is the idea that at a particular level of your abstraction, the API knows nothing about (the details) how something is persisted Implementations of a Repository can deal with persistence, but this should not be exposed in the API of this class (or the interface for the Repository)

Repository UML Diagram

Implementation
1 interface TrackRepositoryInterface { 2 // @return Track[] 3 public function findAll(); public function findById($id); 4 5 public function store(Track $track); 6 7 public function remove(Track $track); 8 }

Implementation (2)
1 class DbTrackRepository 2 implements TrackRepositoryInterface { 3 public function __construct( 4 TrackDbMapper $mapper 5 ) {} 6 /** ... **/ 7 }

Usage
1 2 3 4 5 6 7 $trackRepo = new DbTrackRepository( $services->get('TrackMapper') ); $tracks = $trackRepo->findAll(); foreach ($tracks as $track) { // do something interesting }

Entity, Value Object, and Values


Category: Object Modeling Problem: In both cases, you want to encapsulate a set of data into a conceptual and physical object. This helps separate out the data from the functional components themselves. Sometimes, each object has an identity, a way of identifying a set of data, sometimes not.

Entity, Value Object, and Values


First Solution: Use an array, Return an array from a function or method call, or return a stdClass from a function or method call. Cons: Using an array or stdClass does not guarantee the set of data inside these structures, makes validation harder, makes typing impossible, and does not enforce allow for data safety. Better Solution: Use an Entity or a Value Object

Whats the Difference


An Entity has an identity and a value object does not. Both are generally POPO's (Plain old PHP objects).

Value Objects
By definition, identity free and immutable. Values are simply put, any scalar in PHP (for all intents and purposes). Two separate Entities can share the same reference to a Value Object.

Entity
1 class Artist { 2 public $id; // has identity! 3 public $name; // has identity! 4 public $yearFormed; 5 }

The Classic Example In PHP


... Is not what you think it is. Traditionally, a DateTime object is generally considered a Value Object. Here is why it is not in PHP...

Code sample PHP's DateTime


1 class DateTime { 2 public function modify(/* string */ $modify); 3 public function set*(); public function add(DateInterval $interval); 4 5 }

Value Object
1 /** 2 * NOT PHP's DATETIME!!!! 3 */ 4 class Date { 5 public $year; public $month; 6 7 public $day; 8 }

Value
1 $artist = new Artist; 2 3 // name is a value, a string 4 $artist->name = 'Splender';

Other Patterns
There are a number of patterns/diction not discussed, that need to be at least mentioned What is an Layered Architecture? What are Services? What is an Aggregate + Aggregate Root?

Layered Architecture

Layered Architecture
A way of dividing out software conceptually In PHP, this might happen with some usage of namespaces The type of pattern it implements implies the layer of code it belongs to

Services
An overly used term, has many different contexts Service Layer: separate abstraction layer between controllers and models Model Services: (DDD) A place where "workflows/functions that have no natural place in a value object/entity" Dependency Injection / Application Architecture: shared objects, dependencies (Service Locator)

Aggregate & Aggregate Root (DDD)


A Domain Driven Design Term Aggregate: the series of objects in a model bound together by references and associations Aggregate Root: Only object outside members can hold a reference to, the "entry object", the primary object

Exercise
Let's build something with all that we've learned!

Base Application
https://github.com/ralphschindler/PatternsTutorialApp/

The Idea
I there is money in sharing playlists online. I am not sure what the business will be, but I know it centers around a playlist We need to be able to model Track, Arist and Album information We might want to be able to pull information from web services

The Domain Model

Switch To IDE
Time to switch to IDE, lets explore code

References
E.Gamma, R.Helm, R.Johnson, J.Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, AddisonWesley Professional, 1994 Aaron Saray, Professional PHP Design Patterns, Wrox 2004 Jason E. Sweat, Guide to PHP Design Patterns, Marco Tabini & Associates 2004 Matt Zandstra , PHP Objects, Patterns and Practice, Apress (3 edition) 2010

References (2)
Matthew Weier O'Phinney, Proxies in PHP Giorgio Sironi, Pratical PHP Patterns: Decorator PHP Manual, The Iterator Interface

Resources
https://github.com/ezimuel/PHP-design-patterns https://github.com/ralphschindler/PatternsTutorialApp

Feedback
http://joind.in/6857

Thank You

You might also like