No desesperen, tenemos los builders

Como ya he dicho antes, el estar en contacto con equipos de desarrollo me resulta una experiencia muy valiosa.

Estábamos la semana pasada discutiendo sobre el mejor método para validar objetos del modelo de dominio. Mi primera respuesta ante esa pregunta es: nunca los objetos del modelo debieran estar inválidos, en primer lugar.

Cada objeto de dominio debiera inicializarse completamente en su constructor, ya sea inicializando valores por defecto, ya sea recibiendo valores desde el inicializador.

Algunas veces alguien menciona que no aprecia los constructores con 20 parámetros a lo cual respondo con un cuestionamiento sobre si realmente ese objeto debe ser tan “grande” o si hay uno o mas objetos no descubiertos aun.

Para no hacer esta entrada demasiado larga, supongamos que acordamos que inicializamos completamente el objeto, con valores válidos en el constructor y que ningún método publico nos permite modificarlo dejándolo en estado invalido (1). En este caso, nunca es necesario validar nuestro objeto puesto que sabemos que, si esta instanciado, nunca puede ser inválido.

Y aquí llegamos a la práctica que recomendé a unos colegas la semana pasada: si no es trivial validar una serie de datos y, una vez validados, construir el objeto, entonces usen un Builder. Las responsabilidades del Builder son varias:

  • Asegurarse de tener todos los datos necesarios para construir el objeto
  • Proporcionar una interfaz amigable para la especificación de todos los datos
  • Construir el objeto

A continuación ejemplo con “fluent API”:

public class FacturaBuilder {
    private Cliente _cliente;
    private DateTime _fecha;

    public FacturaBuilder ConCliente(Cliente cliente) {
        _cliente = cliente;
        return this;
    }

    public FacturaBuilder ConFecha(DateTime fecha) {
        _fecha = fecha;
        return this;
    }

    public Factura Build() {
        AssertDatosSuficientesYCorrectos();
        return new Factura(_cliente, _fecha);
    }

    private void AssertDatosSuficientesYCorrectos() {
        if (_cliente == null)
            throw new ArgumentNullException("cliente");

        if (_fecha < DateTime.Today)
            throw new ArgumentOutOfRangeException("fecha");
    }
}

Y este código se usaría de esta manera:

var factura = new FacturaBuilder().
    ConCliente(jose).
    ConFecha(DateTime.Today).
    Build();

Nos vemos!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *