Présentation
Cet article est dans la continuité de l'article sur les iterateurs
Dans cette article, nous avons évoqué que l'utilisation d'un itérateur avait des avantages, mais était contraignante de part leur construction un peu particulière.
La methode fabrique - ou factory method - va vous permettre de vous affranchir de la nature des éléments pour construire des objets. Un exemple très courant d'utilisation de methodes fabrique est la construction d'iterateurs - que ce soit en php, en java ou d'autres langages.
Haut de pageImplémentation du design pattern
Nous reprenons l'exemple de l'iterateur de fichiers:
<?php
/**
* $Id$
* @package Poo_Example
* @subpackage Iterator
*/
if (!class_exists('Iterator_File')) {
/**
*
*/
if (!defined('__EXAMPLE_PATH__')) {
define('__EXAMPLE_PATH__', realpath(dirname(__FILE__).'/../'));
}
require_once __EXAMPLE_PATH__ . '/Autoload.php';
/**
* Definit un iterator sur une collection de fichiers
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @package Poo_Example
* @subpackage Iterator
*/
class Iterator_File implements Iterator_Interface
{
/**
* @var mixed $_collection : Pointeur obtenu par la methode opendir
* @access private
*/
private $_collection = null;
/**
* @var mixed $_currentElement : la valeur de l'element courant
* @access private
*/
private $_currentEelement;
/**
* @var int $currentLine numero de resultat courant
* @access private
*/
private $_currentLine = 0;
/**
* Constructeur
* @access public
* @return void
* @param ressource $collection Pointeur obtenu par la methode opendir
*/
public function __construct(& $collection)
{
if (!is_resource($collection)) {
throw new Exception("cannot instance ".__CLASS__." on non file collection");
}
$this->_collection = & $collection;
$this->next();
}
/**
* return the numero d'enregistrement dans la collection
* @access public
* @return int
*/
public function key()
{
return $this->_currentLine;
}
/**
* Determine si l'iteration est terminee.
* @access public
* @return boolean
*/
public function valid()
{
return ($this->_currentElement !== false);
}
/**
* Itere la collection
* @access public
* @return void
*/
public function next()
{
$this->_currentLine++;
$this->_currentElement = readdir($this->_collection);
}
/**
* Reinitialise l'iterateur sur le premier element de la collection
* @access public
* @return boolean
*/
public function rewind()
{
$this->_currentLine = 1;
rewinddir($this->_collection);
return true;
}
/**
* Retourne l'element courant
* @access public
* @return mixed
*/
public function current()
{
return $this->_currentElement;
}
}
}
L'implémentation de la fabrique va devoir nous retourner un objet Iterator_File sans connaître les éléments pour le fabriquer.
Haut de pageSans ce design pattern
Nous partirons d'une classe très simple qui récupère une liste de fichiers:
<?php
/**
* $Id$
* @package Poo_Example
* @subpackage Factory_Method
*/
if (!class_exists('Folder_Base')) {
/**
* classe de base de listing de fichier
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @package Poo_Example
* @subpackage Factory_Method
*/
class Folder_Base
{
/**
* @var string $_folder : le dossier parcouru
* @access private
*/
var $_folder = '';
/**
* constructeur
* @access public
* @return void
*/
public function __construct($folder)
{
if (!is_dir($folder)) {
throw new Exception("le dossier n'existe pas");
}
$this->_folder = $folder;
}
/**
* recupere la liste des fichiers
* @access public
* @return array
*/
public function getFiles()
{
$dir = opendir($this->_folder);
$files = array();
if ($dir) {
while ($currentElement = readdir($dir)) {
$files[] = $currentElement;
}
}
return $files;
}
}
}
Le script d'éxécution est le suivant:
<?php
/**
* $Id$
* @package Poo_Example
* @subpackage Factory_Method
*/
/**
*
*/
define('__EXAMPLE_PATH__', realpath(dirname(__FILE__).'/../../'));
require_once __EXAMPLE_PATH__ . '/Autoload.php';
/**
* exemple sans utilisation de factory
* @package Poo_Example
* @subpackage Factory_Method
*/
$source = dirname(__FILE__);
$folder = new Folder_Base($source);
$files = $folder->getFiles();
$i = 0;
foreach($files as $current_file) {
echo "fichier: ".++$i." => ". $current_file."\n";
}
?>
L'éxécution de ce script nous donne la sortie suivante:
fichier: 2 => ..
fichier: 3 => With.php
fichier: 4 => Without.php
Avec ce design pattern
Nous remplacons maintenant notre méthode getFiles par une factory method:
<?php
/**
* $Id$
* @package Poo_Example
* @subpackage Factory_Method
*/
if (!class_exists('Folder_Extended')) {
/**
*
*/
if (!defined('__EXAMPLE_PATH__')) {
define('__EXAMPLE_PATH__', realpath(dirname(__FILE__).'/../'));
}
require_once __EXAMPLE_PATH__ . '/Autoload.php';
/**
* classe implementant la factory method
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @package Poo_Example
* @subpackage Factory_Method
*/
class Folder_Extended
{
/**
* @var string $_folder : le dossier parcouru
* @access private
*/
var $_folder = '';
/**
* constructeur
* @access public
* @return void
*/
public function __construct($folder)
{
if (!is_dir($folder)) {
throw new Exception("le dossier n'existe pas");
}
$this->_folder = $folder;
}
/**
* recupere l'iterateur
* @access public
* @return array
* @see Iterator_File
*/
public function getIterator()
{
return new Iterator_File(opendir($this->_folder));
}
}
}
Le script d'éxécution varie quant à lui très peu:
<?php
/**
* $Id$
* @package Poo_Example
* @subpackage Factory_Method
*/
/**
*
*/
define('__EXAMPLE_PATH__', realpath(dirname(__FILE__).'/../../'));
require_once __EXAMPLE_PATH__ . '/Autoload.php';
$source = dirname(__FILE__);
/**
* exemple d'utilisation de factory
* @package Poo_Example
* @subpackage Factory_Method
*/
$folder = new Folder_Extended($source);
// ici on utilise la factory method
$iterator = $folder->getIterator();
while ($iterator->valid()) {
$currentElement = $iterator->current();
echo "fichier: ".$iterator->key()." => ".$currentElement."\n";
$iterator->next();
}
?>
Nous obtenons là encore la meme sortie:
fichier: 2 => ..
fichier: 3 => With.php
fichier: 4 => Without.php
Conclusion
La méthode fabrique va vous permettre de vous abstraire très simplement des problèmes de construction relatif à un objet.
Haut de pageTélécharger les exemples
: 




