Builder = budowniczy.
Wzorzec Builder – rodzaj 1
Jest to klasyczna wersja wzorca Builder.
Zadanie Programistyczne
Smoki mogą być bezskrzydłe lub uskrzydlone. I chociaż proces budowy
jest zawsze taki sam (jaskinia to jaskinia) to produkt końcowy różni się
znacznie. Należy opracować schemat budowy jaskiń dla dewelopera.
Rozwiązanie
Kod umieściłam w pakiecie builder1
.
- Tworzymy klasę abstrakcyjną
JaskiniaBuilder
zawierającą metody
abstrakcyjne dotyczące czynności wykonywanych w procesie budowy jaskini - Tworzymy dwie konkretne klasy rozszerzające tę klasę
JaskiniaBuilder
JaskiniaDlaBezskrzydłychBuilder
JaskiniaDlaUskrzydlonychBuilder
/li>
- Tworzymy klasę
Kierownika
, który kieruje budowniczym i poleca mu wykonanie
czynności w zależności od tego, który to z budowniczych jest potrzebny. - Tworzymy klasę
BuilderFactory,
której jedynym zadaniem jest dopasowanie typu
budowniczego do smoka, dla którego się buduje. - Tworzymy klasę
Developer
pozwalającą przeprowadzić proces budowy.
Klasy JaskiniaDlaBezskrzydlychBuilder
i JaskiniaDlaUskrzydlonychBuilder
opisują szczegóły czynności wykonywanych w procesie budowy jaskini.
Klasa BuilderFactory
może być wykonana również w inny sposób przedstawiony w pakiecie builder1v2
.
Klasa BuilderFactory może być wykonana również w inny sposób przedstawiony w pakiecie builder1v2
.
Obie wyżej wymienione klasy z pakietu builder1v2
powinny być stosowane razem.
Klasa JaskiniaBuilder
może być interfejsem, a nie klasa abstrakcyjną. Zmienia to również klasy JaskiniaDlaBezskrzydlychBuilder
oraz JaskiniaDlaUskrzydlonychBuilder
. Różnice są bardzo małe i polegają na zmianie klasy abstrakcyjnej na interfejs, a extends
na implements
.
Wszystkie trzy klasy umieszczono w pakiecie builder1v3
.
Kody
Pakiet builder1
Klasa BuilderFactory
package builder.builder1; public class BuilderFactory { public JaskiniaBuilder getRodzajSmoka(String str) { JaskiniaBuilder builder = null; if (str.equals(Developer.BEZSKRZYDLY)) { builder = new JaskiniaDlaBezskrzydlychBuilder(); } else if (str.equals(Developer.USKRZYDLONY)) { builder = new JaskiniaDlaUskrzydlonychBuilder(); } return builder; } }
Klasa Developer
package builder.builder1; import java.awt.event.*; import javax.swing.*; public class Developer extends JFrame implements ActionListener { private static final long serialVersionUID = 8791839725719391288L; public static final String BEZSKRZYDLY = "Bezskrzydły"; public static final String USKRZYDLONY = "Uskrzydlony"; public static final String EXIT = "Wyjście"; public Developer() { setLayout(null); setTitle("Budowa Jaskiń"); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); setBounds(0, 0, 450, 400); JButton bezskrzydly = new JButton(BEZSKRZYDLY); bezskrzydly.setBounds(10, 30, 150, 50); bezskrzydly.addActionListener(this); add(bezskrzydly); JButton uskrzydlony = new JButton(USKRZYDLONY); uskrzydlony.setBounds(10, 80, 150, 50); uskrzydlony.addActionListener(this); add(uskrzydlony); JButton exit = new JButton(EXIT); exit.setBounds(10, 130, 150, 50); exit.addActionListener(this); add(exit); setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(Developer::new); } @Override public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals(EXIT)) { System.exit(1); } if (e.getActionCommand().equals(BEZSKRZYDLY)) { // Utworzenie fabryki BuilderFactory factory = new BuilderFactory(); // dopasowanie budowniczego do rodzaju smoka JaskiniaBuilder builder = factory.getRodzajSmoka(BEZSKRZYDLY); // stworzenie kierownika dla budowniczego Kierownk director = new Kierownk(builder); // kierownik wydaje polecenie zbudowania, a budowniczy // buduje director.zbuduj(); } if (e.getActionCommand().equals(USKRZYDLONY)) { BuilderFactory factory = new BuilderFactory(); JaskiniaBuilder builder = factory.getRodzajSmoka(USKRZYDLONY); Kierownk director = new Kierownk(builder); director.zbuduj(); } } }
Klasa JaskiniaBuilder
package builder.builder1; public abstract class JaskiniaBuilder { public abstract void utworzLokalizacje(); public abstract void wybierzOkna(); public abstract void wybierzMaterial(); public abstract void wykonaj(); public String opis() { return "Schemat procesu budowy jaskini"; } }
Klasa JaskiniaDlaBezskrzydlychBuilder
package builder.builder1; public class JaskiniaDlaBezskrzydlychBuilder extends JaskiniaBuilder { @Override public void utworzLokalizacje() { System.out.println("Jaskinia na nizinie"); } @Override public void wybierzOkna() { System.out.println("Okna i drzwi"); } @Override public void wybierzMaterial() { System.out.println("Cegła i wapno"); } @Override public void wykonaj() { System.out.println("Wykonano jaskinię dla bezskrzydłego"); } @Override public String opis() { return "Proces budowy jaskini dla bezskrzydłych"; } }
Klasa JaskiniaDlaUskrzydlonychBuilder
package builder.builder1; public class JaskiniaDlaUskrzydlonychBuilder extends JaskiniaBuilder { @Override public void utworzLokalizacje() { System.out.println("Jaskinia w górach"); } @Override public void wybierzOkna() { System.out.println("Tylko Okna"); } @Override public void wybierzMaterial() { System.out.println("Skała"); } @Override public void wykonaj() { System.out.println("Wykonano jaskinię dla uskrzydlonego"); } @Override public String opis() { return "Proces budowy jaskini dla uskrzydlonych"; } }
Klasa Kierownik
package builder.builder1; public class Kierownk { private final JaskiniaBuilder budowniczy; public Kierownk(JaskiniaBuilder budowniczy) { this.budowniczy = budowniczy; } public void zbuduj() { budowniczy.wybierzMaterial(); budowniczy.wybierzOkna(); budowniczy.wykonaj(); } }
Wynik
Po uruchomieniu klasy Developer otrzymujemy okienko z trzema przyciskami (Rys. 149).
Po kliknięciu przycisku Uskrzydlony otrzymujemy:
Skała Tylko Okna Wykonano jaskinię dla uskrzydlonego
Po kliknięciu przycisku Bezskrzydły otrzymujemy:
Cegła i wapno Okna i drzwi Wykonano jaskinię dla bezskrzydłego
Pakiet builder1v2
Klasa BuilderFactory
package builder.builder1v2; import builder.builder1.JaskiniaBuilder; import builder.builder1.JaskiniaDlaBezskrzydlychBuilder; import builder.builder1.JaskiniaDlaUskrzydlonychBuilder; public class BuilderFactory { private BuilderFactory() { } public static JaskiniaBuilder getRodzajSmoka(String str) { JaskiniaBuilder builder = null; if (str.equals(Developer.BEZSKRZYDLY)) { builder = new JaskiniaDlaBezskrzydlychBuilder(); } else if (str.equals(Developer.USKRZYDLONY)) { builder = new JaskiniaDlaUskrzydlonychBuilder(); } return builder; } }
Klasa Developer
package builder.builder1v2; import builder.builder1.JaskiniaBuilder; import builder.builder1.Kierownk; import java.awt.event.*; import javax.swing.*; public class Developer extends JFrame implements ActionListener { private static final long serialVersionUID = 8791839725719391288L; public static final String BEZSKRZYDLY = "Bezskrzydły"; public static final String USKRZYDLONY = "Uskrzydlony"; public static final String EXIT = "Wyjście"; public Developer() { setLayout(null); setTitle("Budowa Jaskiń"); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); setBounds(0, 0, 450, 400); JButton bezskrzydly = new JButton(BEZSKRZYDLY); bezskrzydly.setBounds(10, 30, 150, 50); bezskrzydly.addActionListener(this); add(bezskrzydly); JButton uskrzydlony = new JButton(USKRZYDLONY); uskrzydlony.setBounds(10, 80, 150, 50); uskrzydlony.addActionListener(this); add(uskrzydlony); JButton exit = new JButton(EXIT); exit.setBounds(10, 130, 150, 50); exit.addActionListener(this); add(exit); setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(Developer::new); } @Override public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals(EXIT)) { System.exit(1); } if (e.getActionCommand().equals(BEZSKRZYDLY)) { JaskiniaBuilder builder = BuilderFactory.getRodzajSmoka(BEZSKRZYDLY); Kierownk director = new Kierownk(builder); director.zbuduj(); } if (e.getActionCommand().equals(USKRZYDLONY)) { JaskiniaBuilder builder = BuilderFactory.getRodzajSmoka(USKRZYDLONY); Kierownk director = new Kierownk(builder); director.zbuduj(); } } }
Pakiet builder1v3
Klasa JaskiniaBuilder
package builder.builder1v3; public interface JaskiniaBuilder { void utworzLokalizacje(); void wybierzOkna(); void wybierzMaterial(); void wykonaj(); }
Klasa JaskiniaDlaBezskrzydlychBuilder
package builder.builder1v3; public class JaskiniaDlaBezskrzydlychBuilder implements JaskiniaBuilder { @Override public void utworzLokalizacje() { System.out.println("Jaskinia na nizinie"); } @Override public void wybierzOkna() { System.out.println("Okna i drzwi"); } @Override public void wybierzMaterial() { System.out.println("Cegła i wapno"); } @Override public void wykonaj() { System.out.println("Wykonano jaskinię dla bezskrzydłego"); } public String opis() { return "Proces budowy jaskini dla bezskrzydłych"; } }
Klasa JaskiniaDlaUsrzydlonychBuilder
package builder.builder1v3; public class JaskiniaDlaUskrzydlonychBuilder implements JaskiniaBuilder { @Override public void utworzLokalizacje() { System.out.println("Jaskinia w górach"); } @Override public void wybierzOkna() { System.out.println("Tylko Okna"); } @Override public void wybierzMaterial() { System.out.println("Skała"); } @Override public void wykonaj() { System.out.println("Wykonano jaskinię dla uskrzydlonego"); } public String opis() { return "Proces budowy jaskini dla uskrzydlonych"; } }
Wzorzec Builder – rodzaj 2
Jest to nowoczesny typ wzorca Builder.
Kod umieściłam w pakiecie builder2
.
Zadanie programistyczne
Smoki tworzą książkę kucharską. Potrzebują obiektu opisującego
potrawy, czyli nazwę, wagę i zawartość poszczególnych składników. Składników
może być dużo, zawsze są określone, ale nie wszystkie z nich musza występować
(np. potrawy nie maja jakiejś witaminy, minerału, czy tłuszczu (składników
zerowych nie uwzględnia się)), a ilość składnika w każdej potrawie
może być inna.
Rozwiązanie
Nie wymaga komentarza. Należy zwrócić uwagę na fakt, ze klasa statyczna i jej
konstruktor są albo publiczne albo z dostępem pakietowym, a konstruktor
klasy zwykłej jest prywatny, czyli klasa Potrawa
nie może utworzyć obiektu.
Obiekt Potrawa
jest tworzony przez wywołanie konstruktora klasy
statycznej.
Kody
Pakiet builder2
Klasa Potrawa
package builder.builder2; public class Potrawa { private final String nazwa; private final int waga; private final int kalorie; private final int tluszcz; private final int weglowodany; private final int bialko; private Potrawa(Builder builder) { nazwa = builder.nazwa; waga = builder.waga; kalorie = builder.kalorie; tluszcz = builder.tluszcz; weglowodany = builder.weglowodany; bialko = builder.bialko; } public String getNazwa() { return nazwa; } public int getWaga() { return waga; } public int getKalorie() { return kalorie; } public int getTluszcz() { return tluszcz; } public int getWeglowodany() { return weglowodany; } public int getBialko() { return bialko; } @Override public String toString() { return nazwa + " " + waga + "g " + kalorie + "kcal " + "tłuszcze:" + tluszcz + " " + "cukry:" + weglowodany + " białko:" + bialko; } static class Builder { // parametry wymagane private final String nazwa; private final int waga; // parametry opcjonalne private int kalorie = 0; private int tluszcz = 0; private int weglowodany = 0; private int bialko = 0; Builder(String nazwa, int waga) { this.nazwa = nazwa; this.waga = waga; } public Builder setKalorie(int kalorie) { this.kalorie = kalorie; return this; } public Builder setTluszcz(int tluszcz) { this.tluszcz = tluszcz; return this; } public Builder setWeglowodany(int weglowodany) { this.weglowodany = weglowodany; return this; } public Builder setBialko(int bialko) { this.bialko = bialko; return this; } public Potrawa build() { return new Potrawa(this); } } }
Klasa Main
package builder.builder2; public class Main { public static void main(String[] args) { Potrawa cocaCola = new Potrawa.Builder("CocaCola", 250).setKalorie(300).setBialko(35).setWeglowodany(27) .build(); System.out.println(cocaCola); System.out.println(cocaCola.getBialko()); } }
Wynik
CocaCola 250g 300kcal tłuszcze:0 cukry:27 białko:35 35