
Budowniczy
Wzorzec budowniczy (ang. builder pattern) jest kreacyjnym wzorcem projektowym, który pozwala na tworzenie skomplikowanych obiektów krok po kroku. Pozwala na budowanie różnych odmian obiektu za pomocą tego samego kodu konstrukcyjnego.
Wyobraźmy sobie, że mamy firmę, która buduje domy. Jak wiemy, budowa domu nie jest prostą sprawą i aby go zbudować potrzebujemy wielu elementów takich jak np. ściany, okna, drzwi, dach, garaż. W zależności od możliwości finansowych klienta możemy wybudować dom w różnych wariantach oraz z różnej jakości materiałów.
Klasa Dom – elementy domu oraz różne warianty budowy domu (konstruktory):
public class Dom {
private String sciany;
private String dach;
private String okna;
private String drzwi;
private String garaz;
public Dom(String sciany, String dach, String okna, String drzwi, String garaz) {
this.sciany = sciany;
this.dach = dach;
this.okna = okna;
this.drzwi = drzwi;
this.garaz = garaz;
}
public Dom(String sciany, String dach) {
this.sciany = sciany;
this.dach = dach;
}
public Dom(String sciany, String dach, String okna, String drzwi) {
this.sciany = sciany;
this.dach = dach;
this.okna = okna;
this.drzwi = drzwi;
}
public String getSciany() {
return sciany;
}
public void setSciany(String sciany) {
this.sciany = sciany;
}
public String getDach() {
return dach;
}
public void setDach(String dach) {
this.dach = dach;
}
public String getOkna() {
return okna;
}
public void setOkna(String okna) {
this.okna = okna;
}
public String getDrzwi() {
return drzwi;
}
public void setDrzwi(String drzwi) {
this.drzwi = drzwi;
}
public String getGaraz() {
return garaz;
}
public void setGaraz(String garaz) {
this.garaz = garaz;
}
@Override
public String toString() {
return "Dom{" +
"sciany='" + sciany + '\'' +
", dach='" + dach + '\'' +
", okna='" + okna + '\'' +
", drzwi='" + drzwi + '\'' +
", garaz='" + garaz + '\'' +
'}';
}
}
Klasa Main – budowa domów:
public class Main {
public static void main(String[] args) {
Dom dom1 = new Dom("Ściany średnie", "Dach standard", "Okna średnie", "Drzwi standard", "Garaż mały");
Dom dom2 = new Dom("Ściany średnie", "Dach nowoczesny");
Dom dom3 = new Dom("Ściany premium", "Dach premium", "Okna premium", "Drzwi premium");
}
}
Jak widać różne warianty domów (konstruktory) zawierają różne elementy. Niektóre domy mogą być wykonane kompleksowo ze wszystkimi elementami i dodatkami, a inne mogą ograniczać się jedynie do budowy ścian. Chcąc uniknąć tworzenia kolejnych konstruktorów z odpowiednimi parametrami możemy wykorzystać wzorzec projektowy budowniczy.
Do rozwiązania problemu użyjemy wzorca projektowego budowniczy z klasą wewnętrzną.
Klasa Dom – po zaimplementowaniu wzorca:
public class Dom {
private String sciany;
private String dach;
private String okna;
private String drzwi;
private String garaz;
private Dom(BudowniczyDomu budowniczyDomu) {
this.sciany = budowniczyDomu.sciany;
this.dach = budowniczyDomu.dach;
this.okna = budowniczyDomu.okna;
this.drzwi = budowniczyDomu.drzwi;
this.garaz = budowniczyDomu.garaz;
}
public String getSciany() {
return sciany;
}
public String getDach() {
return dach;
}
public String getOkna() {
return okna;
}
public String getDrzwi() {
return drzwi;
}
public String getGaraz() {
return garaz;
}
@Override
public String toString() {
return "Dom{" +
"sciany='" + sciany + '\'' +
", dach='" + dach + '\'' +
", okna='" + okna + '\'' +
", drzwi='" + drzwi + '\'' +
", garaz='" + garaz + '\'' +
'}';
}
public static class BudowniczyDomu {
private String sciany;
private String dach;
private String okna;
private String drzwi;
private String garaz;
public BudowniczyDomu budujSciany(String sciany) {
this.sciany = sciany;
return this;
}
public BudowniczyDomu budujDach(String dach) {
this.dach = dach;
return this;
}
public BudowniczyDomu budujOkna(String okna) {
this.okna = okna;
return this;
}
public BudowniczyDomu budujDrzwi(String drzwi) {
this.drzwi = drzwi;
return this;
}
public BudowniczyDomu budujGaraz(String garaz) {
this.garaz = garaz;
return this;
}
public Dom buduj() {
return new Dom(this);
}
}
}
Klasa Main – budowa domu po zaimplementowaniu wzorca:
public class Main {
public static void main(String[] args) {
Dom dom = new Dom.BudowniczyDomu()
.budujSciany("ściany premium")
.budujDach("Dach premium")
.budujDrzwi("Drzwi premium")
.budujOkna("Okna premium")
.buduj();
}
}
Od razu można zauważyć, że obecnie budowa nowego obiektu Dom jest dużo bardziej przejrzysta. W prosty sposób możemy decydować o tym, które pola, z jakimi wartościami będzie zawierał nasz nowy dom.
Co dokładnie zrobiliśmy?
- Do klasy Dom dodaliśmy klasę wewnętrzną “BudowniczyDomu” z takimi samymi polami.
- W klasie “BudowniczyDomu” dodaliśmy metody ustawiające poszczególne wartości tych pól oraz metodę “buduj()” zwracającą nowy obiekt dom.
- Usunęliśmy settery, aby nie można było dokonywać zmian w obiekcie po jego utworzeniu.
- Zamieniliśmy konstruktory różnych wariantów domów na jeden prywatny konstruktor, do którego przekazaliśmy klasę wewnętrzną “BudowniczyDom”.
- We wnętrzu konstruktora przypisaliśmy pola klasy “Dom” do poszczególnych pól klasy “BudowniczyDomu”.
Teraz, aby utworzyć nowy dom, wystarczy:
- W klasie Main zaimplementować nowy obiekt typu Dom.
- Następnie po kropce, za pomocą utworzonych metod, dodawać elementy domu, które nas interesują wraz z ich wartościami.
- Na końcu wywołujemy metodę “buduj()” i cieszymy się z gotowego domu 🙂