FactoryPattern
Da Php-faq.org.
Indice |
[modifica] Il pattern Factory
[modifica] Cosa risolve e quando si applica
[modifica] Implementazione generica in Php
[modifica] Esempio di un possibile uso
Naturalmente gli esempi che seguono presentano codici estremamente semplificati e discutibili sia dal punto di vista del design che dal punto di vista implementativo, ma servono solo a spiegare a grandi linee le potenzialità di questo pattern di programmazione. Questi esempi sono scritti per funzionare con versioni di PHP 5 o superiori (nuove release permettendo) e potrebbero contenere errori :-P.
Assumiamo di avere due tipi di oggetti: `cdrom` e `book`. Tutti e due estendono il tipo `item` ed implementano metodi definiti da un'interfaccia chiamata `itemInterface`.
Quindi avremo qualcosa del genere:
interface itemInterface
{
public function getName();
}
class book
{
protected $bookName;
public function getItemName()
{
return $this->bookName;
}
}
class cdrom
{
protected $cdromName;
public function getItemName()
{
return $this->cdromName;
}
}
Fatto questo assumiamo di dover creare un oggetto di uno dei due tipi ed il criterio di scelta dipenda direttamente dalla variabile `$type`, che può assumere solo tre valori: `cdrom`, `book` e qualsiasi altro valore che genera `NULL` come risultato.
Senza un oggetto del tipo factory dovremmo procedere più o meno così:
if ($type == 'cdrom') {
$newObject = new cdrom();
} else if ($type == 'book') {
$newObject = new book();
} else {
$newObject = NULL;
}
Questo però non è molto comodo, allunga inutilmente il codice (se utilizzato molteplici volte) e non appare molto elegante.
Provando a risolvere il problema con il factory pattern potremmo pensare ad un oggetto di questo tipo:
class itemFactory
{
public static function newItem ($type)
{
switch ($type) {
case 'cdrom': return new cdrom();
case 'book': return new book();
default: return NULL;
}
}
}
A questo punto ogni qualvolta volessimo generare un nuovo oggetto sia del tipo `book` sia del tipo `cdrom`, ci basterebbe fare qualcosa del genere:
$newObject = itemFactory::newItem($type);
Un'altro uso del factory pattern è la facilitazione nell'inizializzazione richiesta da oggetti o comunque da tutte quelle funzionalità che richiedono serie di passi identici o molto simili per essere sfruttate.
Supponiamo di avere un oggetto di nome `paper` che immagazzina informazioni sulla larghezza ed altezza di un foglio (millimetri) in due variabili che chiameremo rispettivamente `width` e `height` che vengono settate tramite due metodi.
Quindi avremo:
class paper
{
public $width, $height;
public function setWidth ($width)
{
$this->width = $width;
}
public function setHeight ($height)
{
$this->height = $height;
}
}
Se adesso volessimo inizializzare due oggetti con le dimensioni dei fogli A4 ed A5 dovremmo procedere specificando i valori esplicitamente, quindi:
$paperA4 = new paper(); $paperA4->setWidth(210); $paperA4->setHeight(297); $paperA5 = new paper(); $paperA5->setWidth(148); $paperA5->setHeight(210);
Questo però non rende molto leggibile e di fatto non piacevolmente breve il codice. Quindi potremmo pensare ad un factory pattern del tipo:
class paperFactory
{
protected static $sizes = array('a4' => array(210, 297), 'a5' => array(148, 210));
public static function newPaper ($size)
{
$paper = new paper();
$paper->setWidth(self::$sizes[$size][0]);
$paper->setHeight(self::$sizes[$size][1]);
return $paper;
}
}
In modo da ottenere lo stesso risultato con un più semplice:
$paperA4 = paperFactory::newPaper('a4');
$paperA5 = paperFactory::newPaper('a5');
Che si presenta molto più esplicativo e conciso nonché facilmente aggiornabile con nuove misure, che magari potremmo estrarre da un DataBase o da un file per non dover toccare più il codice.
