The factory method is one of the fundamental patterns which is both simple and powerful, helping us to delegate responsibilities to other classes and keep code easy to maintain. If write alot of OOP code, you probably use this pattern all the time, whether you realise it or not. ======The Factory Method====== The factory method is a creational method; a method in a class (or even just a PHP function) which returns instances of new classes. The class that owns the factory method is usually called the Creator while the class of object returned by the factory method is usually called the Product. Cutting straight to the example; messages=array( 'Hello World!','Goodbye World!' ); // Shuffle the messages srand ((float)microtime()*1000000); shuffle ($this->messages); } function getMessage() { return $this->messages[0]; } } class MessageMaker { // The factory method... function & makeMessage () { // Return a new instance of RandomMessage return new RandomMessage(); } } $messageMaker=new MessageMaker; for ( $i=0; $i<10; $i++ ) { $randomMessage=& $messageMaker->makeMessage(); echo ( $randomMessage->getMessage().'
' ); } ?>
The MessageMaker class has the factory method makeMessage() which returns new instances of the RandomMessage class. The above example gives us a taste of how useful the factory method can be. Essentially it's helped us //delegate// the work of generating the random messages to the RandomMessage class. This really helps in keeping classes compact and simple, allowing us to keep them focused purely on the job they're supposed to be doing rather than building "god" classes. Also note, with PHP 5 an Java-like exception handling, the factory method will also be a powerful tool to help handle errors - we can place try / catch blocks inside the factory method for example; class MessageMaker { // The factory method... function & makeMessage () { try { // Return a new instance of RandomMessage return new RandomMessage(); } catch ( RandomMessageException $exception ) { echo ( 'A RandomMessage error occurred: '.$exception->toString() ); ) } } ======Layering====== Another (more useful) example of the factory method; // Fetches a list of articles from a database class Articles { var $articles; function Articles ( &$dbConn ) { // Pull the articles from the database $sql="SELECT * FROM articles"; $result = $dbConn->query($sql); while ( $row = $result->getRow() ) { $this->articles[]=$row; } } // Factory method creates new instances of Article function & getArticle () { $row=each($this->articles); return new Article($row['value']); } } // The class built by the factory method class Article { var $title; var $author; var $date; // Unix timestamp var $body; function Article($data) { $this->title=$data->title; $this->author=$data->author; $this->date=$data->date; $this->body=$data->body; } function title() { return htmlspecialchars($this->title); } function author() { return htmlspecialchars($this->author); } function date() { return date('F j, Y',$this->date); } function body() { return strip_tags($this->body, '
'); } } $articles=new Articles($dbConn); // Use the factory method here while ( $article=$articles->getArticle() ) { echo ( "

".$article->title()."

\n" ); echo ( "
" ); echo ( "".$article->author()."" ); echo ( "
\n" ); echo ( "
" ); echo ( "".$article->date()."" ); echo ( "
\n" ); echo ( "
".$article->body()."
\n" ); }
{{design:FactoryMethod.png?200x69}} Looking at the above example it's clearer how powerful the factory method can be. The Article class makes it possible to focus purely on the formatting of the article for display in an HTML page without being bothered by the process of fetching the data from the database. If we choose to switch data sources and pull the articles from a remote web service, for example, the Article class can be re-used without modification, preventing yet more hair loss. **Note:** the Articles class above fetches the //entire// contents of a table and places it in a PHP array. In general this is a bad idea - what if you have 10000+ articles? I'm just doing it here to keep the example code simple (i.e. don't try this at home). ======Factory Recall====== A handy trick in some cases, when using the factory method, is to create the product class and pass it an instance of the creator class at the same time, allowing the product to have access to the creator. This is used to powerful effect in Vincent Oostind's [[http://www.students.cs.uu.nl/people/voostind/eclipse/|Eclipse Library]][[develop:xul_to_phpgtk|XUL to PHP-GTK]] when building the SAX filter in the XulWidget::startElement handler; function startElementHandler($name,$attribs) { if ( is_object ( $this->listener ) ) { $this->listener->startElementHandler($name,$attribs); } else { if ( array_key_exists($name,$this->register) ) { $widget=& new $this->register[$name]($this); $this->setListener($widget); $this->listener->startElementHandler($name,$attribs); } } } I'm using a variable class name here and passing it the current instance of the the filter; $widget=& new $this->register[$name]($this); This allowed me to recursively filter the XUL document to any depth without knowing in advance how deep the XML tree is. The constructed class has access to the class which created it so that it can tell it when it's finished handling all the child XML nodes below it's own depth. Make sense? Makes none to me either ;) Note I said I was taking a break but needed to get this off my chest (and there may still just be time for a look at the Abstract Factory and Builder patterns). ======Resources====== [[http://www.javaworld.com/javaworld/javaqa/2001-05/02-qa-0511-factory.html|Javaworld Q&A on the Factory Method]] - more examples / discussion