A Factory (gyár) minta

A létrehozási minták következő tagja a Factory, avagy a gyár. A neve is mutatja gyártani fogunk vele, mégpedig objektumokat. Hogy miért is van erre szükség, kiderül a cikkből.

A Factory (ismét megjegyzem, hogy nem fogom a magyar megfelelőiket használni a mintáknak) egy általános, viszonylag egyszerű felületet biztosít az objektumok gyártásához, amennyiben különböző típusú (de leginkább hasonló) objektumokat szeretnénk létrehozni.

Vegyük a következő példát, (Hogy mennyire hasznos azt mindenki maga döntse el, szerintem jól példázza a factory lényegét. A magam részéről nem szeretem a new Car() példákat...) html elemeket kell használni és menetközben dől el, hogy azt milyen környezetben és paraméterekkel kell elkészíteni, legyártani. Ez mind PHP, mind Javascript oldalon bemutatható.

PHP példa:

<?php
// A html elem szülőosztálya
class htmlElem{
protected $isXhtml = false; // Xhtml verzió vagy sem
protected $output = ""; // az objektum kimenete
protected $params = array(); // bejövő paraméterek

// A konstruktor beállítja az alap adatokat
public function __construct($params, $isXhtml){
$this->isXhtml = $isXhtml;
$this->params = $params;
// azonnal el is készítjük a kimenetet
$this->build();
}

// string konverzió esetén a kimenetet adjuk vissza
public function __toString(){
return $this->output;
}
// a kimenet készítése
public function build(){
$this->output = "";
}
}
// html input
class heInput extends htmlElem {
public function build(){
$this->output = "<input type='".$this->params['type']."' value='".$this->params['value']."' ".($this->isXhtml?"/":"").">";
}
}
// html meta
class heMeta extends htmlElem {
public function build(){
$this->output = "<meta name='".$this->params['name']."' content='".$this->params['content']."' ".($this->isXhtml?"/":"").">";
}
}
// html factory (singleton, hogy könnyen elérhető legyen, és ebből egyébként is elég egy példány)
class htmlFactory{
// a példány változó
private static $instance = null;
// a beállított Xhtml paraméter
private $isXhtml = false;
// beállítjuk a gyárban, hogy sima vagy xhtml
private function __construct($isXhtml){
$this->isXhtml = $isXhtml;
}

// a példány elkészítése ha még nem lenne
public static function getInstance($isXhtml = false){
if (!isset(self::$instance)){
self::$instance = new htmlFactory($isXhtml);
}
return self::$instance;
}

// factory, ő választja ki melyik objektumot gyártja le és adja nekünk vissza
public function create($tag, $params){
switch($tag){
case "input":
return new heInput($params, $this->isXhtml);
break;
case "meta":
return new heMeta($params, $this->isXhtml);
break;
default:
return false;
break;
}
}
}
// kérünk egy példányt a factory-ból
$htmler = htmlFactory::getInstance(true);
// lekérünk egy input osztályt felparaméterezve
$obj = $htmler->create('input',array("type"=>"text", "value"=>""));
// kimenet (string konverzió)
echo "input: ".$obj;
// lekérünk egy meta osztályt felparaméterezve
$obj = $htmler->create('meta',array("name"=>"keywords", "content"=>"HTML,Javascript,CSS,PHP"));
// kimenet (string konverzió)
echo "meta: ".$obj;
// kimenet:
// input: <input type='text' value='' />meta: <meta name='keywords' content='HTML,Javascript,CSS,PHP' />
?>

A kódot próbáltam jól ellátni kommentekkel, az rögtön látható, hogy a Factory-n kívül a kód még egy mintát tartalmaz, a Singleton-t. Mivel html elemeket akarunk gyártani, ezért könnyen elérhetőnek kell lennie a htmlFactory-nak (ez az egyik ok amiért Singleton is egyben), valamint amikor az első html elemet legyártjuk, már tudni fogjuk, hogy az – esetünkben – Xhtml-e vagy sem, így azt (a környezetet) elég egyszer közölni, tehát a Singleton elképzelés még e felől is maradhat. Azt, hogy a visszakapott html objektumokat igazából nem fogjuk elvileg csak egyszer használni már más kérdés, a kisméretű és átlátható kód miatt egyelőre nem jutott eszembe élhetőbb példa.

A htmlFactory példányosításakor kell a környezeti adatokat átadni, minden gyártáskor ezekkel az adatokkal fogja a html objektumokat gyártani. A create() függvény első $tag paramétere mondja meg, hogy milyen objektumot kell gyártani, a $params második paraméter pedig, az objektum bemenő paraméterei. Mikor meghívjuk a create() függvényt, az eldönti mely osztályból kell egy objektumot legyártani és azt egyszerűen vissza adja nekünk.

A htmlElem ős tartalmazza a különböző html osztályok vázát, ebből származtatjuk a hasonló heInput és heMeta osztályokat, így azokban már csak a build() metódusokat kell megírni.

Javascript példa:


// html input
function heInput(params, isXhtml){
this.output = "";
this.params = params;
this.build = function(){
output = "<input type='"+params.type+"' value='"+params.value+"' "+((isXhtml)?"/":"")+">";
return this;
};
this.toString = function(){return output;};
};
// html meta
function heMeta(params, isXhtml){
this.output = "";
this.params = params;
this.build = function(){
output = "<input name='"+params.name+"' content='"+params.content+"' "+((isXhtml)?"/":"")+">";
return this;
};
this.toString = function(){return output;};
};
// a html Factory ami a html objektumokat fogja gyártani, ez egyben singleton is
var htmlFactory = (function(){
var _instance;
function init(isXhtml){
var _isXhtml = isXhtml;
return {
// a Factory rész
create: function(tag, params){
this.htmlClass = heInput;
switch(tag){
case "input":
this.htmlClass = heInput;
break;
case "meta":
this.htmlClass = heMeta;
break;
default:
break;
};
return new this.htmlClass(params, _isXhtml);
}
};
};
return {
getInstance: function(isXhtml){
if(!_instance){
_instance = init(isXhtml);
}
return _instance;
}
};
})();
// készítünk egy példányt a Factoryból
var htmler = htmlFactory.getInstance(true);
// csinálunk egy inputot
var obj = htmler.create("input",{type:"text", value:"ez az input"});
// kiírjuk azt
// <input type='text' value='ez az input' />
console.log(obj.build().toString());
// késztünk egy meta tag-t
obj = htmler.create("meta",{name:"keywords", content:"HTML,Javascript,CSS,PHP"});
// ezt is kiírjük
// <input name='keywords' content='HTML,Javascript,CSS,PHP' />
console.log(obj.build().toString());

A Javascriptes kód is pontosan azt csinálja, mint a PHP-s, annyi a különbség, hogy a html elemek objektumainál nincs öröklés, azok külön állóak. 

Összegzés:

A Factory minta, akkor használható jól ha:

  • Az objektumok legyártása viszonylag már komplex feladat (és ezt leginkább nem is szeretnénk másra bízni)
  • Sok kis objektummal kell dolgozni, vagy legalább is az objektumoknak több közös tulajdonsága is van
  • Ha egyszerűen szeretnénk több különböző objektumot generálni, de azok függnek a környezetüktől.

Ha tetszett a cikk, véleményed van, kiegészítenéd vagy hibát találtál, írj a cikk alatt egy kommentet, vagy írd meg emailben.

A folytatásban az Abstract Factory következik.

Buy and Trade Bitcoin at Binance