Design patterns
Modello costruttore
Ricerca…
Osservazioni
Separa la costruzione di un oggetto complesso dalla sua rappresentazione in modo che lo stesso processo di costruzione possa creare rappresentazioni differenti.
- Separa la logica dalla rappresentazione.
- Riutilizzare la logica per lavorare con diversi set di dati.
Builder Pattern / C # / Fluent Interrface
public class Email
{
public string To { get; set; }
public string From { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
public class EmailBuilder
{
private readonly Email _email;
public EmailBuilder()
{
_email = new Email();
}
public EmailBuilder To(string address)
{
_email.To = address;
return this;
}
public EmailBuilder From(string address)
{
_email.From = address;
return this;
}
public EmailBuilder Subject(string title)
{
_email.Subject = title;
return this;
}
public EmailBuilder Body(string content)
{
_email.Body = content;
return this;
}
public Email Build()
{
return _email;
}
}
Esempio di utilizzo:
var emailBuilder = new EmailBuilder();
var email = emailBuilder
.To("[email protected]")
.From("[email protected]")
.Subject("Email subject")
.Body("Email content")
.Build();
Builder Pattern / Java Implementation
Il pattern Builder ti consente di creare un'istanza di una classe con molte variabili opzionali in un modo facile da leggere.
Considera il seguente codice:
public class Computer {
public GraphicsCard graphicsCard;
public Monitor[] monitors;
public Processor processor;
public Memory[] ram;
//more class variables here...
Computer(GraphicsCard g, Monitor[] m, Processer p, Memory ram) {
//code omitted for brevity...
}
//class methods omitted...
}
Questo va tutto bene se tutti i parametri sono necessari. Cosa succede se ci sono molte più variabili e / o alcune di esse sono opzionali? Non si desidera creare un numero elevato di costruttori con ciascuna combinazione possibile di parametri obbligatori e facoltativi perché diventa difficile da mantenere e da comprendere per gli sviluppatori. Potresti anche non voler avere una lunga lista di parametri in cui molti potrebbero dover essere inseriti come nulli dall'utente.
Il modello Builder crea una classe interna chiamata Builder che viene utilizzata per creare solo le variabili opzionali desiderate. Questo viene fatto attraverso i metodi per ogni variabile opzionale che prende il tipo di variabile come parametro e restituisce un oggetto Builder in modo che i metodi possano essere concatenati l'uno con l'altro. Tutte le variabili richieste vengono inserite nel costruttore Builder in modo che non possano essere escluse.
Il Builder include anche un metodo chiamato build()
che restituisce l'oggetto in cui si trova e deve essere chiamato alla fine della catena di chiamate al metodo durante la creazione dell'oggetto.
Seguendo l'esempio precedente, questo codice utilizza il modello Builder per la classe Computer.
public class Computer {
private GraphicsCard graphicsCard;
private Monitor[] monitors;
private Processor processor;
private Memory[] ram;
//more class variables here...
private Computer(Builder builder) {
this.graphicsCard = builder.graphicsCard;
this.monitors = builder.monitors;
this.processor = builder.processor;
this.ram = builder.ram;
}
public GraphicsCard getGraphicsCard() {
return this.graphicsCard;
}
public Monitor[] getMonitors() {
return this.monitors;
}
public Processor getProcessor() {
return this.processor;
}
public Memory[] getRam() {
return this.ram;
}
public static class Builder {
private GraphicsCard graphicsCard;
private Monitor[] monitors;
private Processor processor;
private Memory[] ram;
public Builder(Processor p){
this.processor = p;
}
public Builder graphicsCard(GraphicsCard g) {
this.graphicsCard = g;
return this;
}
public Builder monitors(Monitor[] mg) {
this.monitors = mg;
return this;
}
public Builder ram(Memory[] ram) {
this.ram = ram;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
Un esempio di come questa classe verrebbe utilizzata:
public class ComputerExample {
public static void main(String[] args) {
Computer headlessComputer = new Computer.Builder(new Processor("Intel-i3"))
.graphicsCard(new GraphicsCard("GTX-960"))
.build();
Computer gamingPC = new Computer.Builder(new Processor("Intel-i7-quadcode"))
.graphicsCard(new GraphicsCard("DX11"))
.monitors(new Monitor[] = {new Monitor("acer-s7"), new Monitor("acer-s7")})
.ram(new Memory[] = {new Memory("2GB"), new Memory("2GB"), new Memory("2GB"), new Memory("2GB")})
.build();
}
}
Questo esempio mostra come il modello di builder può consentire molta flessibilità nel modo in cui una classe viene creata con un minimo sforzo. L'oggetto Computer può essere implementato in base alla configurazione desiderata del chiamante in modo facile da leggere con poco sforzo.
Modello di generatore in Java con composizione
Intento:
Separa la costruzione di un oggetto complesso dalla sua rappresentazione in modo che lo stesso processo di costruzione possa creare rappresentazioni differenti
Il modello di builder è utile quando hai pochi attributi obbligatori e molti attributi facoltativi per costruire un oggetto. Per creare un oggetto con diversi attributi obbligatori e facoltativi, devi fornire un costruttore complesso per creare l'oggetto. Il modello di costruzione fornisce un semplice processo passo-passo per costruire un oggetto complesso.
Caso di utilizzo della vita reale:
Diversi utenti in FaceBook hanno attributi diversi, che consistono in attributi obbligatori come nome utente e attributi facoltativi come UserBasicInfo e ContactInfo. Alcuni utenti forniscono semplicemente informazioni di base. Alcuni utenti forniscono informazioni dettagliate, tra cui informazioni di contatto. In assenza di pattern Builder, è necessario fornire un costruttore con tutti i parametri obbligatori e facoltativi. Ma il modello Builder semplifica il processo di costruzione fornendo un semplice processo passo-passo per costruire l'oggetto complesso.
Suggerimenti:
- Fornire una classe di build nidificata statica.
- Fornire il costruttore per gli attributi obbligatori dell'oggetto.
- Fornire metodi setter e getter per attributi opzionali dell'oggetto.
- Restituisce lo stesso oggetto Builder dopo aver impostato gli attributi opzionali.
- Fornire il metodo build (), che restituisce l'oggetto complesso
Snippet di codice:
import java.util.*;
class UserBasicInfo{
String nickName;
String birthDate;
String gender;
public UserBasicInfo(String name,String date,String gender){
this.nickName = name;
this.birthDate = date;
this.gender = gender;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("Name:DOB:Gender:").append(nickName).append(":").append(birthDate).append(":").
append(gender);
return sb.toString();
}
}
class ContactInfo{
String eMail;
String mobileHome;
String mobileWork;
public ContactInfo(String mail, String homeNo, String mobileOff){
this.eMail = mail;
this.mobileHome = homeNo;
this.mobileWork = mobileOff;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("email:mobile(H):mobile(W):").append(eMail).append(":").append(mobileHome).append(":").append(mobileWork);
return sb.toString();
}
}
class FaceBookUser {
String userName;
UserBasicInfo userInfo;
ContactInfo contactInfo;
public FaceBookUser(String uName){
this.userName = uName;
}
public void setUserBasicInfo(UserBasicInfo info){
this.userInfo = info;
}
public void setContactInfo(ContactInfo info){
this.contactInfo = info;
}
public String getUserName(){
return userName;
}
public UserBasicInfo getUserBasicInfo(){
return userInfo;
}
public ContactInfo getContactInfo(){
return contactInfo;
}
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("|User|").append(userName).append("|UserInfo|").append(userInfo).append("|ContactInfo|").append(contactInfo);
return sb.toString();
}
static class FaceBookUserBuilder{
FaceBookUser user;
public FaceBookUserBuilder(String userName){
this.user = new FaceBookUser(userName);
}
public FaceBookUserBuilder setUserBasicInfo(UserBasicInfo info){
user.setUserBasicInfo(info);
return this;
}
public FaceBookUserBuilder setContactInfo(ContactInfo info){
user.setContactInfo(info);
return this;
}
public FaceBookUser build(){
return user;
}
}
}
public class BuilderPattern{
public static void main(String args[]){
FaceBookUser fbUser1 = new FaceBookUser.FaceBookUserBuilder("Ravindra").build(); // Mandatory parameters
UserBasicInfo info = new UserBasicInfo("sunrise","25-May-1975","M");
// Build User name + Optional Basic Info
FaceBookUser fbUser2 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
setUserBasicInfo(info).build();
// Build User name + Optional Basic Info + Optional Contact Info
ContactInfo cInfo = new ContactInfo("[email protected]","1111111111","2222222222");
FaceBookUser fbUser3 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
setUserBasicInfo(info).
setContactInfo(cInfo).build();
System.out.println("Facebook user 1:"+fbUser1);
System.out.println("Facebook user 2:"+fbUser2);
System.out.println("Facebook user 3:"+fbUser3);
}
}
produzione:
Facebook user 1:|User|Ravindra|UserInfo|null|ContactInfo|null
Facebook user 2:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|null
Facebook user 3:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|email:mobile(H):mobile(W):[email protected]:1111111111:2222222222
Spiegazione:
FaceBookUser
è un oggetto complesso con gli attributi seguenti che utilizzano la composizione:String userName; UserBasicInfo userInfo; ContactInfo contactInfo;
FaceBookUserBuilder
è una classe di build statica, che contiene e costruisceFaceBookUser
.userName
è solo un parametro obbligatorio per creareFaceBookUser
FaceBookUserBuilder
creaFaceBookUser
impostando parametri opzionali:UserBasicInfo
eContactInfo
Questo esempio illustra tre diversi FaceBookUser con attributi diversi, creati da Builder.
- fbUser1 è stato creato come FaceBookUser con solo attributo userName
- fbUser2 è stato creato come FaceBookUser con userName e UserBasicInfo
- fbUser3 è stato creato come FaceBookUser con userName, UserBasicInfo e ContactInfo
Nell'esempio precedente, la composizione è stata utilizzata invece di duplicare tutti gli attributi di FaceBookUser nella classe Builder.
Nei pattern creativi, inizieremo innanzitutto con pattern semplici come FactoryMethod
e ci muoviamo verso pattern più flessibili e complessi come AbstractFactory
e Builder
.
Java / Lombok
import lombok.Builder;
@Builder
public class Email {
private String to;
private String from;
private String subject;
private String body;
}
Esempio di utilizzo:
Email.builder().to("[email protected]")
.from("[email protected]")
.subject("Email subject")
.body("Email content")
.build();
Modello di generatore avanzato con espressione Lambda di Java 8
public class Person {
private final String salutation;
private final String firstName;
private final String middleName;
private final String lastName;
private final String suffix;
private final Address address;
private final boolean isFemale;
private final boolean isEmployed;
private final boolean isHomewOwner;
public Person(String salutation, String firstName, String middleName, String lastName, String suffix, Address address, boolean isFemale, boolean isEmployed, boolean isHomewOwner) {
this.salutation = salutation;
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
this.suffix = suffix;
this.address = address;
this.isFemale = isFemale;
this.isEmployed = isEmployed;
this.isHomewOwner = isHomewOwner;
}
}
Vecchio modo
public class PersonBuilder {
private String salutation;
private String firstName;
private String middleName;
private String lastName;
private String suffix;
private Address address;
private boolean isFemale;
private boolean isEmployed;
private boolean isHomewOwner;
public PersonBuilder withSalutation(String salutation) {
this.salutation = salutation;
return this;
}
public PersonBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public PersonBuilder withMiddleName(String middleName) {
this.middleName = middleName;
return this;
}
public PersonBuilder withLastName(String lastName) {
this.lastName = lastName;
return this;
}
public PersonBuilder withSuffix(String suffix) {
this.suffix = suffix;
return this;
}
public PersonBuilder withAddress(Address address) {
this.address = address;
return this;
}
public PersonBuilder withIsFemale(boolean isFemale) {
this.isFemale = isFemale;
return this;
}
public PersonBuilder withIsEmployed(boolean isEmployed) {
this.isEmployed = isEmployed;
return this;
}
public PersonBuilder withIsHomewOwner(boolean isHomewOwner) {
this.isHomewOwner = isHomewOwner;
return this;
}
public Person createPerson() {
return new Person(salutation, firstName, middleName, lastName, suffix, address, isFemale, isEmployed, isHomewOwner);
}
Modo avanzato:
public class PersonBuilder {
public String salutation;
public String firstName;
public String middleName;
public String lastName;
public String suffix;
public Address address;
public boolean isFemale;
public boolean isEmployed;
public boolean isHomewOwner;
public PersonBuilder with(
Consumer<PersonBuilder> builderFunction) {
builderFunction.accept(this);
return this;
}
public Person createPerson() {
return new Person(salutation, firstName, middleName,
lastName, suffix, address, isFemale,
isEmployed, isHomewOwner);
}
}
Uso:
Person person = new PersonBuilder()
.with($ -> {
$.salutation = "Mr.";
$.firstName = "John";
$.lastName = "Doe";
$.isFemale = false;
$.isHomewOwner = true;
$.address =
new PersonBuilder.AddressBuilder()
.with($_address -> {
$_address.city = "Pune";
$_address.state = "MH";
$_address.pin = "411001";
}).createAddress();
})
.createPerson();