Patrones de diseño con Flutter: 3— Builder

Paolo Pinto
4 min readApr 12, 2024

--

Cada vez que estamos programando surgen necesidades más robustas en el que facilmente decides partirlas en pedacitos para armarlas. Es cuando tienes la idea de que todo automaticamente ”tiene que estar anidado”. Surge la pregunta ¿Tenemos alguna manera de dividir el proceso de creacion sin sobrecargar nuestro inicio? asas

Se te puede presentar el caso de que un objeto complejo que requiere una inicialización laboriosa, paso a paso, de muchos campos y objetos anidados. Esto puede resultar con un monstruoso constructor que tienen una gran cantidad de parámetros.

Crear una subclase para cada caso de un objeto puede quedar complejo.

¿Que se puede hacer con el patron Builder?

Builder es un patrón de diseño creacional que nos permite construir objetos complejos paso a paso. El patrón nos permite producir distintos tipos y representaciones de un objeto empleando el mismo código de construcción.

fuente: refactoring.guru

El problema se puede solucionar de 2 formas en concreto. Estas dependerán de tus requerimientos del problema como desarrollador:

1. Añade una clase directora

La primera es si requieres de una clase Directora que lo que hace es extraer una serie de llamadas a los pasos del constructor que utilizas para construir un producto. Esto define el orden en el que se deben ejecutar los pasos de construcción, mientras los constructores implementan estos pasos.

2. Sin una clase directora

Tener una clase directora NO es obligatorio ya que se pueden invocar los pasos de construcción en un orden específico. Se hace directamente desde el código cliente. Eso si, se verán los detalles de la construcción del producto en el código cliente.

diagrama de clases patron builder

Cuando vamos a un restaurante tenemos una variedad de hamburguesas, para este caso, utilizaremos la abstracción del patron builder para entregar al cliente los distintos tipos de nuestro menú.

  • Interface(Component): Serán la abstracción de los componentes de cualquier casa, ejemplo: dimensiones, peso, color.
import 'package:flutter/foundation.dart';

abstract class Component {
@protected
late double weight;
@protected
late String name;
@protected
late String color;
@protected
late double width;
@protected
late double height;

double getWidth() => width;

double getHeight() => height;

double getWeight() => weight;

String getColor() => color;

String getName() => name;
}
  • ConcreteBuilders(Concrete Components): Serás las implementaciones de las interfaces, ejemplo: Paredes, Puertas, Ventanas.
import '../components.dart';
class Puerta extends Component {
Puerta() {
name = 'Puerta';
weight = 10;
height = 50;
width = 20;
color = 'Cafe';
}
}
class Ventana extends Component {
Ventana() {
name = 'Ventana';
weight = 5;
height = 5;
width = 5;
color = 'Blanco';
}
}

class Pared extends Component {
Pared() {
name = 'Naranja';
weight = 100;
height = 100;
width = 250;
color = 'Gris';
}
}
  • Clase House(esto solo de la abstraccion clasica de POO):
import 'component.dart';

class House {
House() {
_address = '';
width = 100.0;
height = 100.0;
}
final List<Component> _components = [];
late String _address;
late double width;
late double height;

void addComponent(Component component) => _components.add(component);

String getFormattedComponents() =>
_components.map((x) => x.getName()).join(', ');

void getAdress() => _address;

void setAddress(String address) => _address = address;

void setWidth(double width) => width = width;

void setHeight(double height) => height = height;

}
  • Builders(HouseBuilderBase): Serán la base de una casa, una interface.
import 'package:flutter/foundation.dart';

import 'house.dart';

abstract class HouseBuilderBase {
@protected
late House house;
@protected
late double height;
@protected
late double width;

void createHouse() => house = House();

House getHouse() => house;

void setHouseWidth() => house.setWidth(width);
void setHouseHeight() => house.setHeight(height);

void addParedes();
void addVentanas();
void addPuertas();
}
  • Concrete builders(CasaMuchasVentanas, CasaMuchasPuertas): Es una implementacion de nuestros Builders.
import '../house_builder_base.dart';
import '../components/index.dart';

class CasaMuchasVentanasBuilder extends HouseBuilderBase {
CasaMuchasVentanasBuilder() {
house = House();
height = 500;
width = 400;
}

@override
void addParedes() {
house.addComponent(Pared());
}

@override
void addVentanas() {
house.addComponent(Ventana());
}

@override
void addPuertas() {
house.addComponent(Puerta());
}
}
class CasaMuchasPuertasBuilder extends HouseBuilderBase {
CasaMuchasVentanasBuilder() {
height = 200;
width = 100;
}

@override
void addParedes() {
house.addComponent(Pared());
house.addComponent(Pared());
house.addComponent(Pared());
house.addComponent(Pared());
}

@override
void addVentanas() {
house.addComponent(Ventana());
house.addComponent(Ventana());
}

@override
void addPuertas() {
house.addComponent(Puerta());
house.addComponent(Puerta());
}
}

Director(HouseMaker): Una clase directora que gestiona el proceso de construcción de la casa y retorna el resultado. Se inyecta una implementación específica del constructor en la clase a través del constructor.

import 'house.dart';
import 'house_builder_base.dart';

class HouseMaker {
HouseMaker(this.houseBuilder);

HouseBuilderBase houseBuilder;

// ignore: use_setters_to_change_properties
void changeHouseBuilder(HouseBuilderBase houseBuilder) {
this.houseBuilder = houseBuilder;
}

House getHouse() => houseBuilder.getHouse();

void buildHouse() {
houseBuilder.createHouse();
houseBuilder.setHouseWidth();
houseBuilder.setHouseHeight();

houseBuilder.addVentanas();
houseBuilder.addPuertas();
houseBuilder.addParedes();

}
}

Codigo Cliente(main.dart):

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
final _houseMaker = HouseMaker(CasaMuchasPuertasBuilder());
_houseMaker.changeHouseBuilder(CasaMuchasVentanas());

final data = _houseMaker.getHouse();
return MaterialApp(
title: 'Material App',
theme: ThemeData(
useMaterial3: true
),
home: Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Center(
child: Text(data.width.toString()),
),
),
);
}

Listo, ya implementaste Builder!

Otros artículos para esta serie

Creacionales:

Estructurales:

  • Pronto…

De Comportamiento:

  • Pronto…..

Tu contribución

👏 ¡Presiona el botón de aplaudir a continuación para mostrar tu apoyo y motivarme a escribir mejor!
💬 Deje una respuesta a este artículo brindando sus ideas, comentarios o deseos para la serie.
📢 Comparte este artículo con tus amigos y colegas en las redes sociales.
➕ Sígueme en Medium.
⭐ Ve los ejemplos prácticos desde mi canal en Youtube: Pacha Code

--

--