Jelenlegi hely

25.1.2 Gyártófüggvény (Factory Method) minta

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.

Gyártófüggvény

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.