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.

[modifica] Considerazioni

Strumenti personali