Buscar..


Observaciones

Separa la construcción de un objeto complejo de su representación para que el mismo proceso de construcción pueda crear diferentes representaciones.

  • Separa la lógica de la representación.
  • Reutilizar la lógica para trabajar con diferentes conjuntos de datos.

Patrón del constructor / C # / Interfaz fluida

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;
    }
}

Ejemplo de uso:

var emailBuilder = new EmailBuilder();
var email = emailBuilder
    .To("[email protected]")
    .From("[email protected]")
    .Subject("Email subject")
    .Body("Email content")
    .Build();

Patrón Builder / Implementación Java

El patrón Builder le permite crear una instancia de una clase con muchas variables opcionales de una manera fácil de leer.

Considere el siguiente código:

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...

}

Todo esto está muy bien si todos los parámetros son necesarios. ¿Qué pasa si hay muchas más variables y / o algunas de ellas son opcionales? No desea crear un gran número de constructores con cada combinación posible de parámetros obligatorios y opcionales porque resulta difícil mantenerlos y comprenderlos los desarrolladores. Es posible que tampoco desee tener una larga lista de parámetros en los que el usuario deba ingresar muchos de ellos como nulos.

El patrón Builder crea una clase interna llamada Builder que se utiliza para instanciar solo las variables opcionales deseadas. Esto se realiza a través de métodos para cada variable opcional que toman el tipo de variable como un parámetro y devuelven un objeto Builder para que los métodos se puedan encadenar entre sí. Todas las variables necesarias se colocan en el constructor del generador para que no se puedan omitir.

El Generador también incluye un método llamado build() que devuelve el objeto en el que se encuentra y debe llamarse al final de la cadena de llamadas de métodos al generar el objeto.

Siguiendo con el ejemplo anterior, este código usa el patrón de Generador para la clase de Computadora.

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 ejemplo de cómo se usaría esta clase:

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();
    }

}

Este ejemplo muestra cómo el patrón de constructor puede permitir una gran flexibilidad en la forma en que se crea una clase con bastante poco esfuerzo. El objeto Computadora se puede implementar en función de la configuración deseada de los que llaman de una manera fácil de leer con poco esfuerzo.

Patrón de constructor en Java con composición.

Intención:

Separe la construcción de un objeto complejo de su representación para que el mismo proceso de construcción pueda crear diferentes representaciones

El patrón de generador es útil cuando tiene pocos atributos obligatorios y muchos atributos opcionales para construir un objeto. Para crear un objeto con diferentes atributos obligatorios y opcionales, debe proporcionar un constructor complejo para crear el objeto. El patrón del generador proporciona un proceso paso a paso simple para construir un objeto complejo.

Caso de uso de la vida real:

Los diferentes usuarios de FaceBook tienen atributos diferentes, que consisten en atributos obligatorios como el nombre de usuario y atributos opcionales como UserBasicInfo y ContactInfo. Algunos usuarios simplemente proporcionan información básica. Algunos usuarios proporcionan información detallada que incluye información de contacto. En ausencia del patrón Builder, debe proporcionar un constructor con todos los parámetros obligatorios y opcionales. Pero el patrón Builder simplifica el proceso de construcción al proporcionar un proceso paso a paso simple para construir el objeto complejo.

Consejos:

  1. Proporcionar una clase constructora anidada estática.
  2. Proporcionar constructor para atributos obligatorios de objeto.
  3. Proporcionar métodos de establecimiento y obtención para atributos opcionales del objeto.
  4. Devuelve el mismo objeto Builder después de configurar los atributos opcionales.
  5. Proporcionar el método build (), que devuelve un objeto complejo.

Fragmento de código:

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);
    }
}

salida:

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

Explicación:

  1. FaceBookUser es un objeto complejo con los siguientes atributos que utilizan composición:

    String userName;
    UserBasicInfo userInfo;
    ContactInfo contactInfo;
    
  2. FaceBookUserBuilder es una clase de constructor estático, que contiene y construye FaceBookUser .

  3. userName es solo un parámetro obligatorio para construir FaceBookUser

  4. FaceBookUserBuilder construye FaceBookUser configurando parámetros opcionales: UserBasicInfo y ContactInfo

  5. Este ejemplo ilustra tres diferentes FaceBookUsers con diferentes atributos, construidos desde Builder.

    1. fbUser1 se creó como FaceBookUser con solo el atributo userName
    2. fbUser2 fue creado como FaceBookUser con userName y UserBasicInfo
    3. fbUser3 fue creado como FaceBookUser con userName, UserBasicInfo y ContactInfo

En el ejemplo anterior, se ha utilizado la composición en lugar de duplicar todos los atributos de FaceBookUser en la clase Builder.

En los patrones de creación, primero comenzaremos con patrones simples como FactoryMethod y FactoryMethod hacia patrones más flexibles y complejos como AbstractFactory y Builder .

Java / Lombok

import lombok.Builder;

@Builder
public class Email {

    private String to;
    private String from;
    private String subject;
    private String body;

}

Ejemplo de uso:

Email.builder().to("[email protected]")
        .from("[email protected]")
        .subject("Email subject")
        .body("Email content")
        .build();

Patrón de generador avanzado con Java 8 expresión Lambda

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;
 }
}

Vieja forma

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);
}

Manera avanzada:

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();

Consulte: https://medium.com/beingprofessional/think-functional-advanced-builder-pattern-using-lambda-284714b85ed5#.d9sryx3g9



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow