Builder
Proprietati
Tip: Creational, Obiect
Nivel: Componenta
Scop
Simplificarea crearii obiectelor prin definirea unei clase a carei scop este sa construiasca instante ale altei clase. sablonul Builder produce un produs principal; în produs pot fi mai multe clase, dar exista întotdeauna o clasa principala.
Introducere. Exemplu de problema: PIM (Personal Information Manager)
Într-un PIM, utilizatorii doresc sa gestioneze un calendar social. Pentru a permite acest lucru, se poate defini o clasa numita Appointment care sa contina in 343g614d formatia pentru un singur eveniment, si anume:
Date de început si de sfârsit
Descrierea întâlnirii
Locul unde se desfasoara întâlnirea
Participantii la întâlnire.
Informatia de mai sus este completata de utilizator, când acesta stabileste întâlnirea, prin urmare se va defini un constructor care permite setarea starii noului obiect Appointment
De ce este nevoie pentru a crea o întâlnire? În functie de tipul specific al întâlnirii este nevoie de diverse informatii. Unele întâlniri necesita o lista de participanti (întâlnirea lunara a membrilor unui club de film). Altele necesita precizarea datelor de început si de sfârsit (o conferinta care dureaza mai multe zile), iar altele au loc într-o singura zi (vizitarea unei expozitii de pictura). Având în vedere toate aceste alternative posibile, crearea unui obiect Appointment nu este o sarcina triviala.
Exista doua posibilitati de gestionare a crearii obiectelor, nici una foarte atractiva: se creeaza constructori pentru fiecare tip specific de întâlnire sau se scrie un singur constructor ce înglobeaza o logica functionala complicata. Fiecare dintre abordari are dezavantaje: folosirea mai multor constructori face ca logica de apel sa devina mai complexa, iar logica functionala înglobata în unicul constructor mareste complexitatea codului acestuia si îngreuneaza depanarea. Mai rau, ambele abordari au potential de a crea dificultati daca se doreste derivarea unor alte clase din Appointment
Solutia eleganta este delegarea responsabilitatii crearii obiectelor Appointment la o clasa speciala AppointmentBuilder, simplificând semnificativ codul clasei Appointment. Clasa AppointmentBuilder contine metode de creare a diverselor tipuri particulare de obiecte Appointment, iar clientul va apela acele metode ale clasei AppointmentBuilder care sunt relevante pentru tipul de întâlnire dorit.
Suplimentar, AppointmentBuilder poate verifica daca informatia transmisa pentru crearea obiectului Appointment este valida, ajutând la întarirea regulilor de activitate. Daca se doreste derivarea clasei Appointment, se va crea fie un nou builder, fie se va deriva cel existent. În ambele cazuri, sarcina este mai usoara decât alternativa gestionarii initializarii obiectelor prin folosirea constructorilor.
Aplicabilitate
sablonul Builder se foloseste când o clasa:
Are o structura interna complexa (în special una cu o multime variabila de obiecte înrudite).
Are atribute ce depind unul de altul. Unul din lucrurile ce le poate face un Builder este sa întareasca construirea în etape succesive a unui obiect complex. Aceasta ar fi necesara când atributele obiectului Product depind unul de altul. De exemplu, sa presupunem ca se construieste o comanda. Trebuie sa ne asiguram ca în adresa destinatarului este completat câmpul Stat înainte ca sa se efectueze calculele pentru expediere (deoarece impozitul aplicat difera de la stat la stat în SUA, iar costul include si impozitul).
Foloseste alte obiecte din sistem care ar putea fi greu de obtinut în timpul crearii.
Descriere
Deoarece acest sablon este dedicat construirii de obiecte complexe din surse posibil diferite, el se numeste Builder. Pe masura ce crearea obiectului creste în complexitate, gestionarea crearii obiectului prin constructor poate deveni dificila. Aceasta este cu atât mai adevarat cu cât obiectul nu depinde exclusiv de resursele care sunt sub propriul sau control.
Obiectele specifice activitatii (obiectele ce implementeaza logica aplicatiei, business objects, BO) intra de regula în aceasta categorie. Ele necesita frecvent pentru initializare date dintr-o baza de date si ar putea avea nevoie sa se asocieze cu un numar arbitrar de alte BO pentru a reprezenta cât mai fidel modelul activitatii (business model).
Un alt exemplu se refera la obiectele compuse dintr-un sistem, precum obiectul ce reprezinta un desen într-un program de editare vizuala. Un astfel de obiect ar putea avea nevoie sa fie legat de un numar arbitrar de alte obiecte, imediat dupa ce este creat.
În astfel de situatii, este convenabil sa se defineasca o alta clasa (Builder) care are ca sarcina construirea obiectului. Clasa Builder coordoneaza asamblarea obiectului produs: crearea resurselor, memorarea rezultatelor intermediare si furnizarea structurii functionale pentru creare. Suplimentar, Builder poate achizitiona resurse sistem pentru construirea obiectului produs.
Implementare
Diagrama
de clase pentru sablonul Builder este prezentata în Figura 1.2
Figura 1.2. Diagrama de clase a sablonului Builder
Pentru implementarea sablonului Builder, este nevoie de:
Director - Are o referinta la o instanta AbstractBuilder. Obiectul Director apeleaza metodele creationale folosind instanta sa builder pentru a obtine diversele parti din care se asambleaza apoi obiectul produs.
AbstractBuilder - Interfata care defineste metodele disponibile pentru crearea partilor separate ale produsului.
ConcreteBuilder - Clasa ce implementeaza interfata AbstractBuilder. Clasa ConcreteBuilder implementeaza toate metodele necesare pentru crearea unui obiect Product real. Implementarea metodelor stie cum sa prelucreze informatia din obiectul Director si construieste partile respective ale obiectului Product. Clasa ConcreteBuilder are fie o metoda getProduct, fie o metoda creationala ce întoarce o instanta a clasei Product
Product - Obiectul produs. Poate fi fie interfata (de preferat), fie clasa.
Avantaje si dezavantaje
Avantaje:
sablonul Builder simplifica gestionarea fluxului general de creare a obiectelor complexe. Aceasta simplificare se manifesta în doua moduri:
Pentru obiectele ce impun o creare pas cu pas (este necesar un sir de pasi pentru a face obiectul complet activ), Builder actioneaza ca un obiect de nivel mai înalt care supervizeaza procesul de creare. El poate coordona si valida crearea tuturor resurselor si, la nevoie, poate furniza o strategie de avarie la aparitia erorilor.
Pentru obiectele care au nevoie la crearea lor de resurse sistem, precum conexiunile la BD sau la BO existente, sablonul Builder ofera un punct central de gestiune a resurselor. De asemenea, Builder se constituie într-un punct unic de control creational pentru produsul sau, care poate fi folosit de alte obiecte din sistem. Ca si în cazul altor sabloane creationale, aceasta abordare simplifica lucrurile pentru clientii sistemului, deoarece ei au nevoie doar de acces la obiectul Builder pentru a produce o resursa.
Dezavantaje:
Dezavantajul major este prezenta unei cuplari strânse între sablonul Builder, produsul sau si orice alti delegati creationali folositi la construirea obiectului. Modificarile care se fac pentru produsul creat de Builder implica de obicei modificari în Builder si în delegati.
Variatiuni la acest sablon
La nivelul cel mai fundamental, este posibila implementarea unui schelet de sablon Builder în jurul unei singure clase Builder cu metoda creationala si produsul sau. Pentru a obtine o flexibilitate mai mare, proiectantii extind adesea acest sablon de baza folosind una dintre abordarile:
Se creeaza un Builder abstract. Prin definirea unei clase abstracte sau a unei interfete care specifica metodele creationale, se produce un sistem mai generic care poate gazdui potential mai multe feluri de Builder-i.
Se definesc pentru Builder mai multe metode create. Unele sabloane Builder definesc mai multe metode (în esenta, ele supraîncarca metoda lor creationala) pentru a furniza o varietate de modalitati de initializare a resursei construite.
Se proiecteaza delegati creationali. În aceasta abordare, un obiect Director poseda metoda create generala pentru obiectele Product si apeleaza o serie de metode create de granularitate mai mica ale obiectului Builder. În acest caz, obiectul Director actioneaza ca manager pentru procesul creational al sablonului Builder.
sabloane înrudite
Un sablon înrudit este Composite. sablonul Builder este folosit frecvent pentru a produce obiecte Composite, deoarece acestea au o structura foarte complexa.
Exemplu
Exemplul urmator ilustreaza folosirea sablonului Builder la crearea unei întâlniri în PIM. Lista ce urmeaza prezinta sumar scopul fiecareia dintre clasele folosite.
AppointmentBuilder, MeetingBuilder - clase Builder
Scheduler - clasa Director
Appointment - clasa (interfata) Product
Address, Contact - Clase de sprijin, folosite pentru a pastra informatia relevanta pentru o întâlnire (Appointment)
InformationRequiredException - Clasa Exception ce se produce când informatia furnizata nu este suficienta.
Pentru sablonul de baza, AppointmentBuilder gestioneaza crearea unui produs complex, în cazul nostru obiectul Appointment.
Clasa AppointmentBuilder foloseste o serie de metode create - buildAppointment, buildLocation, buildDates si buildAttendees - pentru a crea un obiect Appointment si a-l popula cu date.
Exemplul 1 AppointmentBuilder.java
1. import java.util.Date;
2. import java.util.ArrayList;
4. public class AppointmentBuilder
public void buildDates(Date startDate, Date endDate)
if ((endDate != null) && (endDate.after(startDate)))
}
public void buildDescription(String newDescription)
public void buildAttendees(ArrayList attendees)
}
public void buildLocation(Location newLocation)
}
public Appointment getAppointment() throws InformationRequiredException
if (appointment.getLocation() == null)
if (appointment.getAttendees().isEmpty())
if (requiredElements > 0)
return appointment;
}
public int getRequiredElements()
Exemplul 2 Appointment.java
1. import java.util.ArrayList;
2. import java.util.Date;
3. public class Appointment
public Date getEndDate()
public String getDescription()
public ArrayList getAttendees()
public Location getLocation()
public void setDescription(String newDescription)
public void setLocation(Location newLocation)
public void setStartDate(Date newStartDate)
public void setEndDate(Date newEndDate)
public void setAttendees(ArrayList newAttendees)
}
public void addAttendee(Contact attendee)
}
public void removeAttendee(Contact attendee)
public String toString()
Clasa Scheduler foloseste apeluri ale metodelor lui AppointmentBuilder, gestionând procesul creational prin metoda createAppointment
Exemplul 3 Scheduler.java
1. import java.util.Date;
2. import java.util.ArrayList;
3. public class Scheduler
builder.buildAppointment();
builder.buildDates(startDate, endDate);
builder.buildDescription(description);
builder.buildAttendees(attendees);
builder.buildLocation(location);
return builder.getAppointment();
Responsabilitatile fiecarei clase sunt rezumate în continuare:
Scheduler - Apeleaza metodele create adecvate ale obiectului AppointmentBuilder; returneaza apelatorului un obiect Appointment complet.
AppointmentBuilder - Contine metode create si întareste regulile specifice aplicatiei; creeaza obiectul Appointment curent.
Appointment - Obiectul supus crearii, ce contine informatie despre o întâlnire.
Clasa MeetingBuilder din Examplul 4 demonstreaza unul dintre beneficiile sablonului Builder. Pentru a adauga reguli suplimentare pentru obiectele Appointment, se extinde sablonul Builder existent. În acest caz, clasa MeetingBuilder introduce o restrictie suplimentara: pentru un obiect Appointment de tip întâlnire (meeting), trebuie specificate datele de început si de sfârsit.
Exemplul 4 MeetingBuilder.java
1. import java.util.Date;
2. import java.util.Vector;
4. public class MeetingBuilder extends AppointmentBuilder
finally
if (requiredElements > 0)
}
return appointment;
}
|