Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерн Строитель (Builder)
Паттерн Строитель (Builder Pattern) — это порождающий паттерн проектирования, который используется для пошагового создания сложных объектов. Вместо того чтобы передавать все параметры в конструктор, мы строим объект методом цепи (fluent interface).
Зачем нужен Строитель
Об объекты с множеством параметров сложны в использовании:
// СЛОЖНО — много параметров, легко ошибиться
final user = User(
'John',
'john@example.com',
'+1234567890',
'New York',
30,
true,
false,
null,
null,
true,
);
Строитель решает эту проблему:
// ПРОСТО и ПОНЯТНО
final user = UserBuilder()
.setName('John')
.setEmail('john@example.com')
.setPhone('+1234567890')
.setAge(30)
.setEmailVerified(true)
.build();
Структура паттерна
// 1. Класс, который нужно создать (объект)
class Pizza {
final String size;
final String crust;
final List<String> toppings;
final bool extraCheese;
final bool spicy;
Pizza({
required this.size,
required this.crust,
required this.toppings,
required this.extraCheese,
required this.spicy,
});
@override
String toString() {
return 'Pizza(size: $size, crust: $crust, toppings: $toppings, extraCheese: $extraCheese, spicy: $spicy)';
}
}
// 2. Строитель
class PizzaBuilder {
late String _size;
late String _crust;
List<String> _toppings = [];
bool _extraCheese = false;
bool _spicy = false;
PizzaBuilder size(String size) {
if (size != 'S' && size != 'M' && size != 'L') {
throw ArgumentError('Invalid size');
}
_size = size;
return this;
}
PizzaBuilder crust(String crust) {
if (crust != 'thin' && crust != 'thick' && crust != 'stuffed') {
throw ArgumentError('Invalid crust');
}
_crust = crust;
return this;
}
PizzaBuilder addTopping(String topping) {
_toppings.add(topping);
return this;
}
PizzaBuilder addToppings(List<String> toppings) {
_toppings.addAll(toppings);
return this;
}
PizzaBuilder extraCheese(bool value) {
_extraCheese = value;
return this;
}
PizzaBuilder spicy(bool value) {
_spicy = value;
return this;
}
Pizza build() {
if (_size == null) throw StateError('Size is required');
if (_crust == null) throw StateError('Crust is required');
return Pizza(
size: _size,
crust: _crust,
toppings: _toppings,
extraCheese: _extraCheese,
spicy: _spicy,
);
}
}
// Использование
final pizza = PizzaBuilder()
.size('L')
.crust('thick')
.addTopping('pepperoni')
.addTopping('mushrooms')
.extraCheese(true)
.spicy(true)
.build();
print(pizza);
Пример: сложный SQL запрос
class QueryBuilder {
late String _table;
List<String> _select = ['*'];
List<String> _where = [];
List<String> _orderBy = [];
int? _limit;
int? _offset;
QueryBuilder from(String table) {
_table = table;
return this;
}
QueryBuilder select(List<String> columns) {
_select = columns;
return this;
}
QueryBuilder where(String condition) {
_where.add(condition);
return this;
}
QueryBuilder orderBy(String column, {bool ascending = true}) {
final direction = ascending ? 'ASC' : 'DESC';
_orderBy.add('$column $direction');
return this;
}
QueryBuilder limit(int count) {
_limit = count;
return this;
}
QueryBuilder offset(int count) {
_offset = count;
return this;
}
String build() {
final query = StringBuffer('SELECT ');
query.write(_select.join(', '));
query.write(' FROM $_table');
if (_where.isNotEmpty) {
query.write(' WHERE ');
query.write(_where.join(' AND '));
}
if (_orderBy.isNotEmpty) {
query.write(' ORDER BY ');
query.write(_orderBy.join(', '));
}
if (_limit != null) {
query.write(' LIMIT $_limit');
}
if (_offset != null) {
query.write(' OFFSET $_offset');
}
return query.toString();
}
}
// Использование
final query = QueryBuilder()
.from('users')
.select(['id', 'name', 'email'])
.where('age >= 18')
.where('country = "USA"')
.orderBy('name')
.limit(10)
.offset(5)
.build();
print(query);
// SELECT id, name, email FROM users WHERE age >= 18 AND country = "USA" ORDER BY name ASC LIMIT 10 OFFSET 5
Builder в контексте Flutter
class DialogBuilder {
late String _title;
late String _message;
final List<DialogButton> _buttons = [];
String? _iconPath;
bool _dismissible = true;
DialogBuilder title(String title) {
_title = title;
return this;
}
DialogBuilder message(String message) {
_message = message;
return this;
}
DialogBuilder addButton(String label, VoidCallback onPressed) {
_buttons.add(DialogButton(label: label, onPressed: onPressed));
return this;
}
DialogBuilder icon(String path) {
_iconPath = path;
return this;
}
DialogBuilder dismissible(bool value) {
_dismissible = value;
return this;
}
Widget build(BuildContext context) {
return AlertDialog(
title: Text(_title),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (_iconPath != null) Image.asset(_iconPath!, height: 64),
Text(_message),
],
),
actions: _buttons.map((btn) {
return TextButton(
onPressed: btn.onPressed,
child: Text(btn.label),
);
}).toList(),
);
}
}
class DialogButton {
final String label;
final VoidCallback onPressed;
DialogButton({required this.label, required this.onPressed});
}
// Использование в Flutter
showDialog(
context: context,
builder: (context) {
return DialogBuilder()
.title('Подтверждение')
.message('Вы уверены?')
.icon('assets/confirm.png')
.addButton('Отмена', () => Navigator.pop(context))
.addButton('Согласен', () {
// обработка
Navigator.pop(context);
})
.build(context);
},
);
Преимущества Builder паттерна
- Читаемость — код очень понятный и самодокументирующийся
- Гибкость — можно опускать необязательные параметры
- Валидация — можно проверять данные на каждом шаге или в build()
- Цепочка вызовов — fluent interface делает код приятнее
- Слабая связанность — изменения в объекте не влияют на клиентский код
Когда использовать
- Объекты с множеством параметров (более 4-5)
- Сложные объекты с взаимозависимыми параметрами
- Когда нужна валидация при конструировании
- Когда нужны разные конфигурации одного объекта
Builder паттерн — это мощный инструмент для создания сложных объектов в понятной и гибкой форме.