Problem do rozwiązania:
- Potrzebujemy elastyczności w tworzeniu nowych obiektów, inicjując tylko niektóre pola klasy.
- Chcemy zapewnić swobodę przy tworzeniu obiektów, ale po ich powstaniu nie dopuszczamy zmian.
- Chcemy uniknąć tworzenia dużej liczby konstruktorów z wieloma polami, które trzeba przekazać do utworzenia obiektu.
lub
- Nie chcemy dawać elastyczności przy tworzeniu nowych obiektów przez użytkownika.
- Definicje, jak skonstruować dany obiekt będą przypisane w innych klasach.
Opis wzorca Builder:
Wzorzec ten możemy zaimplementować na dwa sposoby:
- Poprzez klasę wewnętrzną;
- Poprzez interfejs
Schemat UML rozwiązania z klasą wewnętrzną:

Schemat działania:
W rozwiązaniu z klasą wewnętrzną, w klasie House występują tylko prywatne pola i ich gettery (nie definiujemy setterów pól klasy „budowanej”).
- Za wytworzenie obiektów klasy House odpowiada inna klasa, tj. wewnętrzna klasa HouseBuiler.
- Klasa HouseBuilder ma zdublowane prywatne pola z klasy budowanej i publiczne metody typu HouseBuilder, ustawiające zdublowane pola wewnątrz swojego ciała na wartości przekazane poprzez metody „budujące”.
- Wywołując poszczególne metody budujące HouseBuildera np. buildWalls(String walls), inicjalizujemy obiekt i przypisujemy przekazane poprzez metody wartości do pól prywatnych klasy HouseBuiler.
- Co istotne, na końcu każdej takiej metody zwracamy obiekt this (po kawałku tworzymy obiekt, inicjalizując poszczególne, wybrane pola metodami) .
- W finalnej metodzie build() ostatecznie zwracamy cały nowo zdefiniowany obiekt typu House, przekazując poprzez konstruktor this ostatecznie stworzony obiekt HouseBuildera.
- W konstruktorze klasy House następuje przypisanie pól z HouseBuildera do prywatnych pól klasy House.
Fragment klasy main:
House house = new House.HouseBuilder()
.buildWalls("walls")
.buildFloors("floors")
.buildRoof("roof")
.buildRooms("rooms")
.build();
Schemat UML rozwiązania z interfejsem:

Schemat działania:
W rozwiązaniu z Interfejsem, w klasie House występują prywatne pola, ich gettery oraz settery.
- W interfejsie HouseBuilder deklarujemy metody budujące, odpowiadające budowaniu pól klasy House oraz metodę typu House getHouse().
- Za wytworzenie obiektów klasy House odpowiadają inne klasy tj. dyrektor oraz tzw. buildery, w których definiujemy metody stanowiące, jak będzie wyglądał nasz dom (implementujące interfejs HouseBuilder).
- Builder jak np. SmallHouseBuilder zawiera prywatne pole typu House i nadpisanie metod z interfejsu jako settery z klasy House dla prywatnego, własnego pola typu House („budowanie” obiektu następuje według metod z tej klasy, według określonego przez nas „przepisu” po wywołaniu odpowiednich metod).
- Całością procesu budowy zarządza dyrektor, tj. klasa HouseDirector. Zawiera ona prywatne pole typu HouseBuilder, konstruktor, metodę budującą buildHouse (to w jej definicji są wywołane metody HouseBuildera, niekoniecznie wszystkie i w takiej kolejności, jak w klasie buildera, generalnie jak wymyśli to sobie dyrektor, bo to on zarządza budową) i metodę typu House getHouse().
- Na początku tworzymy obiekty klas implementujących interfejs HouseBuilder np. smallHauseBuilder.
- Następnie, tworząc obiekt dyrektora, przekazujemy mu w konstruktorze utworzony obiekt.
- Po utworzeniu obiektu dyrektora, możemy na nim wywołać metodę buildHouse(), a wiec wybudować obiekt według wytycznych dyrektora.
- Jeśli chcemy zobaczyć nasz wybudowany obiekt, to wywołujemy metodę getHouse() klasy HouseDirectior (która to z kolei zwraca metodę getHouse() konkretnego buildera).
Fragment klasy main:
SmallHouseBuilder smallHouseBuilder = new SmallHouseBuilder();
HouseDirectior smallHouseDirector = new HouseDirectior(smallHouseBuilder);
smallHouseDirector.buildHouse();
House smallHouse = smallHouseDirector.getHouse();
Kod programu przed zastosowaniem wzorca:
Klasa main:
import House.House;
public class Main {
public static void main(String[] args) {
House house1 = new House("walls", "floors", "rooms", "roof", "windows", "doors");
House house2 = new House("walls", "floors", "roof");
System.out.println(house1);
System.out.println(house2);
}
}
Klasa House:
package House;
public class House {
private String walls;
private String floors;
private String rooms;
private String roof;
private String windows;
private String doors;
private String garage;
public House(String walls, String floors, String rooms, String roof, String windows, String doors, String garage) {
this.walls = walls;
this.floors = floors;
this.rooms = rooms;
this.roof = roof;
this.windows = windows;
this.doors = doors;
this.garage = garage;
}
public House(String walls, String floors, String rooms, String roof, String windows, String doors) {
this.walls = walls;
this.floors = floors;
this.rooms = rooms;
this.roof = roof;
this.windows = windows;
this.doors = doors;
}
public House(String walls, String floors, String roof) {
this.walls = walls;
this.floors = floors;
this.roof = roof;
}
public String getWalls() {
return walls;
}
public void setWalls(String walls) {
this.walls = walls;
}
public String getFloors() {
return floors;
}
public void setFloors(String floors) {
this.floors = floors;
}
public String getRooms() {
return rooms;
}
public void setRooms(String rooms) {
this.rooms = rooms;
}
public String getRoof() {
return roof;
}
public void setRoof(String roof) {
this.roof = roof;
}
public String getWindows() {
return windows;
}
public void setWindows(String windows) {
this.windows = windows;
}
public String getDoors() {
return doors;
}
public void setDoors(String doors) {
this.doors = doors;
}
public String getGarage() {
return garage;
}
public void setGarage(String garage) {
this.garage = garage;
}
@Override
public String toString() {
return "House{" +
"walls='" + walls + '\'' +
", floors='" + floors + '\'' +
", rooms='" + rooms + '\'' +
", roof='" + roof + '\'' +
", windows='" + windows + '\'' +
", doors='" + doors + '\'' +
", garage='" + garage + '\'' +
'}';
}
}
Kod programu po zastosowaniu wzorca z klasą wewnętrzną:
Klasa main:
import House.House;
public class Main {
public static void main(String[] args) {
House house = new House.HouseBuilder()
.buildWalls("walls")
.buildFloors("floors")
.buildRoof("roof")
.buildRooms("rooms")
.build();
System.out.println(house);
}
}
Klasa House:
package House;
public class House {
private String walls;
private String floors;
private String rooms;
private String roof;
private String windows;
private String doors;
private String garage;
private House(HouseBuilder houseBuilder){
this.walls = houseBuilder.walls;
this.floors = houseBuilder.floors;
this.rooms = houseBuilder.rooms;
this.roof = houseBuilder.roof;
this.windows = houseBuilder.windows;
this.doors = houseBuilder.doors;
this.garage = houseBuilder.garage;
}
public String getWalls() {
return walls;
}
public String getFloors() {
return floors;
}
public String getRooms() {
return rooms;
}
public String getRoof() {
return roof;
}
public String getWindows() {
return windows;
}
public String getDoors() {
return doors;
}
public String getGarage() {
return garage;
}
@Override
public String toString() {
return "House{" +
"walls='" + walls + '\'' +
", floors='" + floors + '\'' +
", rooms='" + rooms + '\'' +
", roof='" + roof + '\'' +
", windows='" + windows + '\'' +
", doors='" + doors + '\'' +
", garage='" + garage + '\'' +
'}';
}
public static class HouseBuilder {
private String walls;
private String floors;
private String rooms;
private String roof;
private String windows;
private String doors;
private String garage;
public HouseBuilder buildWalls(String walls){
this.walls = walls;
return this;
}
public HouseBuilder buildFloors(String floors){
this.floors = floors;
return this;
}
public HouseBuilder buildRooms(String rooms){
this.rooms = rooms;
return this;
}
public HouseBuilder buildRoof(String roof){
this.roof = roof;
return this;
}
public HouseBuilder buildWindows(String windows){
this.windows = windows;
return this;
}
public HouseBuilder buildDoors(String doors){
this.doors = doors;
return this;
}
public HouseBuilder buildGarage(String garage){
this.garage = garage;
return this;
}
public House build(){
return new House(this);
}
}
}
Kod programu po zastosowaniu wzorca z interfejsem:
Klasa main:
import house.BigHouseBuilder; import house.House; import house.HouseDirectior; import house.SmallHouseBuilder;
public class Main {
public static void main(String[] args) {
SmallHouseBuilder smallHouseBuilder = new SmallHouseBuilder();
HouseDirectior smallHouseDirector = new HouseDirectior(smallHouseBuilder);
smallHouseDirector.buildHouse();
House smallHouse = smallHouseDirector.getHouse();
BigHouseBuilder bigHouseBuilder = new BigHouseBuilder();
HouseDirectior bigHouseDirector = new HouseDirectior(bigHouseBuilder);
bigHouseDirector.buildHouse();
House bigHouse = bigHouseDirector.getHouse();
System.out.println(smallHouse);
System.out.println(bigHouse);
}
}
Klasa House:
package house;
public class House {
private String walls;
private String floors;
private String rooms;
private String roof;
private String windows;
private String doors;
private String garage;
public String getWalls() {
return walls;
}
public void setWalls(String walls) {
this.walls = walls;
}
public String getFloors() {
return floors;
}
public void setFloors(String floors) {
this.floors = floors;
}
public String getRooms() {
return rooms;
}
public void setRooms(String rooms) {
this.rooms = rooms;
}
public String getRoof() {
return roof;
}
public void setRoof(String roof) {
this.roof = roof;
}
public String getWindows() {
return windows;
}
public void setWindows(String windows) {
this.windows = windows;
}
public String getDoors() {
return doors;
}
public void setDoors(String doors) {
this.doors = doors;
}
public String getGarage() {
return garage;
}
public void setGarage(String garage) {
this.garage = garage;
}
@Override
public String toString() {
return "House{" +
"walls='" + walls + '\'' +
", floors='" + floors + '\'' +
", rooms='" + rooms + '\'' +
", roof='" + roof + '\'' +
", windows='" + windows + '\'' +
", doors='" + doors + '\'' +
", garage='" + garage + '\'' +
'}';
}
}
Klasa HouseDirector:
package house;
public class HouseDirectior {
private HouseBuilder houseBuilder;
public HouseDirectior(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
public void buildHouse(){
houseBuilder.buildWalls();
houseBuilder.buildFloors();
houseBuilder.buildRooms();
houseBuilder.buildRoof();
houseBuilder.buildWindows();
houseBuilder.buildDoors();
houseBuilder.buildGarage();
}
public House getHouse(){
return this.houseBuilder.getHouse();
}
}
Interfejs HouseBuilder:
package house;
public interface HouseBuilder {
void buildWalls();
void buildFloors();
void buildRooms();
void buildRoof();
void buildWindows();
void buildDoors();
void buildGarage();
House getHouse();
}
Klasa SmallHouseBuilder:
package house;
public class SmallHouseBuilder implements HouseBuilder {
private House house;
public SmallHouseBuilder() {
this.house = new House();
}
@Override
public void buildWalls() {
this.house.setWalls("small walls");
}
@Override
public void buildFloors() {
this.house.setFloors("small floors");
}
@Override
public void buildRooms() {
this.house.setRooms("small rooms");
}
@Override
public void buildRoof() {
this.house.setRoof("small roof");
}
@Override
public void buildWindows() {
this.house.setWindows("small windows");
}
@Override
public void buildDoors() {
this.house.setDoors("small doors");
}
@Override
public void buildGarage() {
this.house.setGarage("small garage");
}
@Override
public House getHouse() {
return house;
}
}
Klasa BigHouseBuilder:
package house;
public class BigHouseBuilder implements HouseBuilder{
private House house;
public BigHouseBuilder() {
this.house = new House();
}
@Override
public void buildWalls() {
this.house.setWalls("big walls");
}
@Override
public void buildFloors() {
this.house.setFloors("big floors");
}
@Override
public void buildRooms() {
this.house.setRooms("big rooms");
}
@Override
public void buildRoof() {
this.house.setRoof("big roof");
}
@Override
public void buildWindows() {
this.house.setWindows("big windows");
}
@Override
public void buildDoors() {
this.house.setDoors("big doors");
}
@Override
public void buildGarage() {
this.house.setGarage("big garage");
}
@Override
public House getHouse() {
return house;
}
}
