Hogy micsodát, kérem szépen? Na mindjárt! Először is, jó lenne egy konstruktor paraméter, ahol az ablak fejlécének a szövegét lehet átadni! Egy String!
public class Window extends JFrame {
// default serial id baromsag
private static final long serialVersionUID = 1L;
public Window(String text) {
setTitle(text);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
Ok, akkor setTitle(text), mezei paraméter, minden okés.
Aztán az is jó lenne ám, ha néha még ikont is lehetne beállítani az ablaknak. Meg persze az ablak tartalmát. Meg ezt. Meg azt. Meg amazt is - így könnyen eljutunk 20-30 konstuktor paraméterig.
Persze ez nem kényelmes, mert legtöbbször csak az ablak szövegét akarjunk beállítani. De másszor meg mást is, így egyszerűen kedveskedünk magunknak annyival, hogy többféle konstruktort csinálunk - más-más paraméterlistával.
A Swing készítői is így tettek, így húhú, van pár variáció:
A JLabel esetén egészen kreatívok voltak:
Szóval van sok konstruktorunk. Ami jó ötletnek tűnt, csak az a baj, hogy hamar a visszájára fordul. Ezt a dolgot, amikor sok-sok konstruktorunk van, egyre több plusz paraméterrel, na ezt nevezik úgy, hogy telescoping constructors (azaz "teleszkópos" konstruktorok). A szoftvertechnológia jelenlegi tudása szerint ez tervezési hibának számít, mert az alábbi két problémát hordozza magával.
Te kitalálod, hogy mit csinál az alábbi kód?
JLabel helloLabel=new JLabel(valami,akarmi);
Bevallom, nekem fogalmam sincs. Először is, meg kellene nézni a valami és az akarmi változó típusát, utána kitalálni, hogy vajon melyik konstruktor paramétereihez stimmelnek, és máris tudjuk, hogy ez, izé... vagy a 4. vagy az 5. konstruktor, szóval vagy ikont adunk meg valami vízszintes igazítással, vagy szöveget vízszintes igazítással... argh!
Igaz, hogy van vagy 4-5 konstruktor, de a konstruktorban még mindig nincsen meg egy csomó egyéb paraméter, méret, szín, betűtípus, ezerféle dolog! Ezért ezeknek settere van, ahogy azt a 07-es részben láttuk.
Akkor most vajon a setText-el, vagy a megfelelő konstruktor hívásával kell beállítani a szöveget? Tulajdonképpen mindkettő működik... de ez pontosan kétszer több lehetőség és bonyolítás, ugye? Ráadásul most fejben fogjuk tartani, hogy éppen mit lehet konstruktorral, és mit lehet setterrel állítgatni? Jajj!
Igazából úgy gondolták megoldani ezeket a problémákat, hogy minden dologra van setter, ugyanakkor a leggyakrabban használt dolgokra van konstruktor paraméter is, így a setter hívását meg lehet spórolni, így:
JLabel helloLabel=new JLabel();
helloLabel.setText("Hello!");
és megspórolva a setText-et a konstruktor paraméterrel:
JLabel helloLabel=new JLabel("Hello!");
Nos, szakértő marketingesek erre azt mondanák, hogy 50% kód-megtakarítás! Pont feleakkora a program! Tehát ügyesek voltunk! Bár szerintem Dulifulinak biztos más lenne erről a véleménye...
A mai évek megoldása a builder pattern. A pattern azt jelenti, hogy "minta", és jelen esetben nem azt jelenti, hogy csíkos, avagy pöttyös lesz-e az osztályunk. A szó a design-patternre (tervezési mintára) utal, ami pedig olyan jól bevált módszerek gyűjteménye, amire manapság a modern szoftverek épülnek.
Mint ahogy az OOP a való élet objektumait modellezik, a legtöbb design pattern a való élet megoldásait modellezi. A builder azt jelenti, hogy "építő".
Te már voltál fagyizóban, igaz? No, de tudsz fagyit készíteni? Én nem tudok fagyit készíteni, mégis, ha fagyit szeretnék, tudom, hogy mit kell csinálni: egy fagyizóba kell menni, és a fagyis néniek elmondani, hogy:
és ez után lesz egy fagyim!
Hogy ennek mi a köze a konstruktorainkhoz? Elég sok! Először is, nagyon nehéz lenne olyan konstruktort csinálni, ami fagyit készít, hiszen előre nem tudjuk, hogy mennyi gombócot kell legyártani. Akkor csináljunk 1, 2, 3, 4 gombócos konstruktort? Meg 1 gombóc + feltét, meg 1 gombóc + feltét 1 + feltét 2 konstruktort is, hiszen van, aki tejszínhabot kér, van aki öntetet... brrr....
Elég sok gond van itt tehát:
Na ezt paraméterezgesse valaki! Sokkal célszerűbb megoldás az, ha létrehozunk egy builder osztályt - az IcecreamBuilder-t, aminek van egy csomó metódusa, amivel mindent be lehet állítani, majd a végén a build metódusát meghívva létrejön a megfelelő fagyi - egy Icecream példány.
Kódban ez így nézne ki:
Icecream icecream=new IcecreamBuilder()
.addScoop("csoki")
.addScoop("málna")
.addScoop("citrom")
.setWaffel("édes tölcsér")
.addTopping("tejszínhab")
.addSauce("csokiöntet")
.build();
Umm, ez erősen hasonlít arra, amit a fagyisnéninek mondunk, igaz? :) Na ez a builder pattern - azaz mezei Java osztályok és mezei Java metódusok okos felhasználása abból a célból, hogy valamit sokkal kifejezőbben tudjunk leprogramozni.
Ó, és még valami: ezek az addIzék meg minden más is metódus hívás. Ez két okból jó:
Na akkor, hogy nézne ki egy mezei 1 gombóc csoki, az alap tölcsérben?
Icecream icecream=new IcecreamBuilder()
.addScoop("csoki")
.build();
Csoki, dupla öntettel
Icecream icecream=new IcecreamBuilder()
.addScoop("csoki")
.addSauce("csokiöntet")
.addSauce("málnaöntet")
.build();
Csak egy kis tejszínhab:
Icecream icecream=new IcecreamBuilder()
.addTopping("tejszínhab")
.build();
Akkor sincs baj, ha össze-vissza mondjuk:
Icecream icecream=new IcecreamBuilder()
.addTopping("tejszínhab")
.addSauce("málnaöntet")
.addScoop("csoki")
.build();
Lehet össze-vissza - hiszen a fagyit még nem kezdtük el összerakni, csak majd a build híváskor, addig csak a rendelést vettük fel.
Hm, ez egész jó!
Tehát akkor az Icecream (a fagyi) amit felépítünk, és az IcecreamBuilder (a fagyisnéni) aki "összeépíti" a kívánságainknak megfelelő fagyit.
No de hogyan tudunk ilyen buildert csinálni?