A gyártófüggvény minta az egyik legtöbbet alkalmazott tervezési minta. A minta célja egy objektum létrehozása különböző információk alapján.
A következő ábrán a bemeneti információt az abc jelképezi. Ez alapján a gyártófüggvény az x ősosztály valamelyik leszármazottját (xy vagy xz) fogja példányosítani. A getClass hívására létrejövő objektum tényleges típusáról többnyire nem is kell tudnia a felhasználónak.
Nézzünk egy konkrét példát. A feladatunk az, hogy a nevek kezelése körüli következő problémát megoldjuk. Az angol nyelvben kétféle módon is megadhatjuk ugyanazt a nevet:
- Jack London
- London, Jack
Ha egy beviteli mezőben a felhasználó megadja a nevét, akkor bármelyiket használja. Nekünk az a feladatunk, hogy a név alapján egy olyan objektumot hozzuk létre, amelyikből bármikor elérhetők a szükséges szolgáltatások.
Először nézzük meg azt az ősosztályt, amelynek a szolgáltatásaira végső soron szükségünk lesz:
abstract class Namer {
protected String last;
protected String first;
public String getFirst() {
return first;
}
public String getLast() {
return last;
}
}
Nézzük meg a két igen egyszerű leszármazott osztályt is.
Az első leszármazottunk a név megadásánál az első ( szóközös) megadást feltételezi.
class FirstFirst extends Namer {
public FirstFirst(String s) {
int i = s.lastIndexOf(" ");
if (i > 0) {
first = s.substring(0, i).trim();
last =s.substring(i+1).trim();
} else {
first = "";
last = s;
}
}
}
A másik leszármazott a vessző karaktert keresi elválasztóként:
class LastFirst extends Namer {
public LastFirst(String s) {
int i = s.indexOf(",");
if (i > 0) {
last = s.substring(0, i).trim();
first = s.substring(i + 1).trim();
} else {
last = s;
first = "";
}
}
}
A tényleges példányosítást (gyártást) a következő osztály végzi:
class NameFactory {
public Namer getNamer(String entry) {
int i = entry.indexOf(",");
if (i>0)
return new LastFirst(entry);
else
return new FirstFirst(entry);
}
}
Elegendő a getNamer
metódust a nevet tartalmazó String
paraméterrel meghívni, eredményül pedig egy Namer
(leszármazott) objektumot kapunk.
Megjegyezés: A példa láttán felmerülhet az a kifogás, hogy elegendő lett volna a Namer
osztály konstruktorában ezt a kétféle inputot megkülönbözteti. Ennél a példánál tényleg járható lenne ez az út is.
A példa egyszerűsége abban rejlik, hogy a leszármazottak csak a konstruktorunkban térnek el egymástól. Más összetettebb szituáció esetén a leszármazottak érdemi működése is jelentősen eltérhet egymástól.
Legerősebb érvként pedig azt érdemes meggondolni, hogy ha a bemutatott struktúrát kell bővítenünk egy újfajta viselkedéssel, akkor elegendő egy új leszármazott osztály létrehozása és a getNamer
metódus bővítése, a többi osztályhoz egyáltalán nem kell hozzányúlni. Ez egy nagyobb alkalmazás esetén nagyon erőteljes érv lehet.