Sablonul de proiectare Builder

Descriere

Se utilizeaza atunci cand avem o clasa cu un numar mare de atribute, dintre care cateva sunt obligatorii iar restul optionale.

O prima varianta ar fi cea in care am defini cate un constructor pentru fiecare combinatie posibila de atribute. In acest caz codul poate deveni greu de gestionat in cazul in care numarul de atribute creste.

public User(String firstName, String lastName) {
    this(firstName, lastName, 0);
}
 
public User(String firstName, String lastName, int age) {
    this(firstName, lastName, age, '');
}
 
public User(String firstName, String lastName, int age, String phone) {
    this(firstName, lastName, age, phone, '');
}
 
public User(String firstName, String lastName, int age, String phone, String address) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.phone = phone;
    this.address = address;
}

O a doua varianta ar fi cea in care declaram un constructor gol si apoi, prin intermediul unor setere am permite initializarea pe rand a fiecaruia dintre atribute. In acest caz apare o problema legata de consitenta obiectului intruct dupa creearea acestuia, pana in momentul apelarii setterelor obiectul are atributele neinitializate si ar putea fi accesat in aceasta stare. Exista de asemenea posibilitatea ca programatorul sa uite initializarea atributelor.

public class User {
	private String firstName; // required
	private String lastName; // required
	private int age; // optional
	private String phone; // optional
	private String address;  //optional
 
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
}

Intr-o astfel de situatie varianta optima este utilizarea sablonului de proiectare Builder prezentat in exemplul de mai jos.

Nota: Varianta de Builder prezentat in aceasta sectiune este diferita de sablonul original descris in cartea Design Patterns: Elements of Reusable Object-Oriented Software, unde era descrisa o metoda de abstractizare a procesului de construire a unor obiecte complexe.

Presentarea de fata are la baza acest articol.

Exemplu

public class User {
	private final String firstName; // required
	private final String lastName; // required
	private final int age; // optional
	private final String phone; // optional
	private final String address; // optional
 
	private User(UserBuilder builder) {
		this.firstName = builder.firstName;
		this.lastName = builder.lastName;
		this.age = builder.age;
		this.phone = builder.phone;
		this.address = builder.address;
	}
 
	public String getFirstName() {
		return firstName;
	}
 
	public String getLastName() {
		return lastName;
	}
 
	public int getAge() {
		return age;
	}
 
	public String getPhone() {
		return phone;
	}
 
	public String getAddress() {
		return address;
	}
 
        public String toString(){
            return "["+firstName+":"+lastName+":"+address+":"+age+":"+phone+"]";
        }
 
 
 
	public static class UserBuilder {
		private final String firstName;
		private final String lastName;
		private int age;
		private String phone;
		private String address;
 
		public UserBuilder(String firstName, String lastName) {
			this.firstName = firstName;
			this.lastName = lastName;
		}
 
		public UserBuilder age(int age) {
			this.age = age;
			return this;
		}
 
		public UserBuilder phone(String phone) {
			this.phone = phone;
			return this;
		}
 
		public UserBuilder address(String address) {
			this.address = address;
			return this;
		}
 
		public User build() {
			return new User(this);
		}
 
	}
}
 
public class Test {
 
    public static void main(String[] args){
        User u1 = new
			User.UserBuilder("Jhon", "Doe")
			.age(30)
			.phone("1234567")
			.address("Fake address 1234")
			.build();
 
                User u2 = new
			User.UserBuilder("Jhon", "Doe")
			.age(30)
			.phone("1234567")
			.build();
 
        System.out.println(u1);
        System.out.println(u2);
    }
}