Wzorzec projektowy Builder

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.

  1. Tworzymy klasę abstrakcyjną JaskiniaBuilder zawierającą metody
    abstrakcyjne dotyczące czynności wykonywanych w procesie budowy jaskini
  2. Tworzymy dwie konkretne klasy rozszerzające tę klasę JaskiniaBuilder
    • JaskiniaDlaBezskrzydłychBuilder
    • JaskiniaDlaUskrzydlonychBuilder</li>
  3. 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.
  4. Tworzymy klasę BuilderFactory, której jedynym zadaniem jest dopasowanie typu
    budowniczego do smoka, dla którego się buduje.
  5. 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).


Rys. 149. Trzy przyciski

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

]]>

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *