The Builder Pattern in Dart

The Builder pattern separates the construction of a complex object from its representation. It’s particularly useful in Dart when you have objects with many optional parameters.

The problem

final user = User(
  name: 'Ildeberto',
  age: 23,
  email: 'ildeberto34@gmail.com',
  role: Role.admin,
  // ... 10 more optional fields
);

Constructors with many parameters become unreadable and error-prone.

The solution

class UserBuilder {
  String _name = '';
  int _age = 0;
  String _email = '';
  Role _role = Role.user;

  UserBuilder name(String name) { _name = name; return this; }
  UserBuilder age(int age) { _age = age; return this; }
  UserBuilder email(String email) { _email = email; return this; }
  UserBuilder role(Role role) { _role = role; return this; }

  User build() => User(name: _name, age: _age, email: _email, role: _role);
}

Usage becomes expressive and readable:

final user = UserBuilder()
  .name('Ildeberto')
  .age(23)
  .email('ildeberto34@gmail.com')
  .role(Role.admin)
  .build();

Dart’s copyWith alternative

For immutable value objects, Dart’s copyWith pattern covers similar ground:

final updated = user.copyWith(role: Role.admin);

Use the Builder pattern when construction involves validation logic or multi-step assembly. Use copyWith for simple immutable data classes.