Tehát akkor:
public class Window extends JFrame {
private static final long serialVersionUID = 1L;
private Window(Builder builder) {
setTitle(builder.text);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static class Builder {
private String text;
public Builder text(String text) {
this.text=text;
return this;
}
public Window build() {
return new Window(this);
}
}
}
Hm, nem is volt nehéz, igaz? Na jó, azért nem biztos, hogy elsőre így kezdtük volna - de már látszik, hogy előnyünkre lesz!
Ha további tulajdonságokat kell hozzátenni, akkor:
Az ablakot pedig a fluent builderrel könnyen összeépíthetjük, így:
public class WindowTest {
public static void main(String[] args) {
new Window.Builder()
.text("Hello")
.build();
}
}
No most, miért nem
Window window=new Window.Builder()
.text("Hello")
.build();
Miért nem jegyezzük meg a legyártott Window példányt egy változóban? Azért nem, mert semmi szükségünk nincs rá. A legyártott ablak megjelenik a képernyőn - és eltűnik, ha bezárod. Mivel soha többet nem használjuk a programban, felesleges lenne egy változóba tenni, amit utána semmire nem használunk. Logikus? :)
A 06-os részben sok szó esett a getterek és a setterek elnevezéséről. De milye van egy buildernek? Az biztos, hogy nem getterei, hiszen semmi értelmeset nem adnak vissza (csak a buildert magát a fluent interface kedvéért). Akkor ennek setterei lennének? Tulajdonképpen nem, mert valójában nem állít be még semmit - mert még nincs fagyi csak a build() meghívása után fog történni valami.
Sok elképzelés létezik, de a közmegegyezés az, hogy a builder egy deklaratív dolog, ezért a metódusainak a neve egyszerűen főnév. Tehát nem setText() hanem csak text(). Kivételt képeznek azok a metódusok, amik többszörösen hívva nem átírják a már létező értékeket, hanem hozzáteszik az új értéket, tehát addScoop() - ami hozzátesz egy gombócot, és nem pedig átírja a gombóc ízét.
A deklaratív szóval egyre többet fogunk találkozni. Ez röviden azt jelenti, hogy ahelyett, hogy részletesen a számítógépnek megparancsolnánk, hogy hogyan csináljon valamit, mi csak azt mondjuk meg, hogy mit csináljon. Ez az apró különbség valójában hatalmas, hiszen deklaratív módon sokkal rövidebben, és tisztábban fogalmazhatjuk meg a céljainkat. (Teljes programnyelvek vannak, amik kizárólag deklaratív módon programozhatók! A Java gyárilag egy buta imperatív nyelv, de miért is ne próbálnánk meg szebben, deklaratívabban használni?)
Imperatív: (azaz parancsoló, szóval nem-deklaratív)
Deklaratív: (azaz szándékainkat kinyilvánító)
Amit most a fluent builderrel elértünk, az már erősen deklaratív érzés! Nézzük csak meg:
Imperatív: - sima Swing, szájbarágósan minden műveletet leírunk:
public static void main(String[] args) {
JFrame frame=new JFrame(); // csinálj egy ablakot
frame.setTitle("Hello"); // változtasd meg a szövegét
frame.pack(); // pakold össze - bármit is jelentsen ez
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // ezt is csináld
frame.setVisible(true); // tedd láthatóvá
}
Deklaratív: - a szándékainkat fejezzük ki, semmi mást nem írunk le:
public class WindowTest {
public static void main(String[] args) {
new Window.Builder() // legyen egy ablak
.text("Hello") // legyen a felirata hello
.build(); // csináld meg
}
}
A különbség még szembetűnőbb lesz később, ahogy egyre több dolgot tud majd a saját kis mini-frameworkünk!
A deklaratív esetben sokkal kevesebb, sokkal logikusabb, sokkal kifejezőbb kódot írunk - és hagyjuk, hogy a framework amit csinálunk majd szájbarágja a részleteket a Swingnek, ami megcsinálja a tényleges melót.