← Назад к вопросам

Что такое паттерн Builder?

2.2 Middle🔥 122 комментариев
#Архитектура Flutter#ООП и паттерны

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Паттерн Builder

Builder — это паттерн проектирования, который позволяет пошагово конструировать сложные объекты. Вместо того чтобы передавать все параметры в конструктор, мы строим объект методом цепи вызовов.

Проблема, которую решает Builder

Без Builder (ПЛОХО)

class User {
  final String name;
  final String email;
  final String? phone;
  final String? address;
  final int? age;
  final bool emailVerified;
  final bool phoneVerified;
  final String? avatar;
  final String? bio;
  
  User(
    this.name,
    this.email,
    this.phone,
    this.address,
    this.age,
    this.emailVerified,
    this.phoneVerified,
    this.avatar,
    this.bio,
  );
}

// Использование — вспоминать порядок параметров сложно!
final user = User(
  'John Doe',
  'john@example.com',
  '+1234567890',
  null,
  null,
  true,
  false,
  null,
  'Software Developer',
);

С Builder (ХОРОШО)

class User {
  final String name;
  final String email;
  final String? phone;
  final String? address;
  final int? age;
  final bool emailVerified;
  final bool phoneVerified;
  final String? avatar;
  final String? bio;
  
  const User({
    required this.name,
    required this.email,
    this.phone,
    this.address,
    this.age,
    this.emailVerified = false,
    this.phoneVerified = false,
    this.avatar,
    this.bio,
  });
}

// Использование — чётко, понятно!
final user = User(
  name: 'John Doe',
  email: 'john@example.com',
  phone: '+1234567890',
  emailVerified: true,
  bio: 'Software Developer',
);

В Dart часто используют именованные параметры вместо классического Builder паттерна, но Builder всё ещё полезен в более сложных случаях.

Классический Builder паттерн

// Конечный объект
class HttpRequest {
  final String url;
  final String method;
  final Map<String, String> headers;
  final dynamic body;
  final Duration timeout;
  final bool followRedirects;
  
  HttpRequest({
    required this.url,
    required this.method,
    required this.headers,
    required this.body,
    required this.timeout,
    required this.followRedirects,
  });
  
  @override
  String toString() {
    return 'HttpRequest(url: $url, method: $method, headers: $headers, body: $body, timeout: $timeout, followRedirects: $followRedirects)';
  }
}

// Builder класс
class HttpRequestBuilder {
  late String _url;
  String _method = 'GET';
  Map<String, String> _headers = {};
  dynamic _body;
  Duration _timeout = const Duration(seconds: 30);
  bool _followRedirects = true;
  
  // Setter методы, которые возвращают this для цепочки вызовов
  HttpRequestBuilder url(String url) {
    _url = url;
    return this;
  }
  
  HttpRequestBuilder method(String method) {
    _method = method;
    return this;
  }
  
  HttpRequestBuilder header(String key, String value) {
    _headers[key] = value;
    return this;
  }
  
  HttpRequestBuilder headers(Map<String, String> headers) {
    _headers.addAll(headers);
    return this;
  }
  
  HttpRequestBuilder body(dynamic body) {
    _body = body;
    return this;
  }
  
  HttpRequestBuilder timeout(Duration timeout) {
    _timeout = timeout;
    return this;
  }
  
  HttpRequestBuilder followRedirects(bool value) {
    _followRedirects = value;
    return this;
  }
  
  // Финальный метод, который создаёт объект
  HttpRequest build() {
    if (_url.isEmpty) {
      throw ArgumentError('URL is required');
    }
    
    return HttpRequest(
      url: _url,
      method: _method,
      headers: _headers,
      body: _body,
      timeout: _timeout,
      followRedirects: _followRedirects,
    );
  }
}

// Использование
final request = HttpRequestBuilder()
  .url('https://api.example.com/users')
  .method('POST')
  .header('Content-Type', 'application/json')
  .header('Authorization', 'Bearer token')
  .body('{"name": "John"}')
  .timeout(const Duration(seconds: 60))
  .build();

print(request);

Builder для сложных UI элементов

// Класс для конфигурации кнопки
class ButtonConfig {
  final String label;
  final VoidCallback onPressed;
  final ButtonStyle? style;
  final Color? backgroundColor;
  final Color? textColor;
  final double? width;
  final double? height;
  final EdgeInsets padding;
  final BorderRadius borderRadius;
  final double fontSize;
  final FontWeight fontWeight;
  
  const ButtonConfig({
    required this.label,
    required this.onPressed,
    this.style,
    this.backgroundColor,
    this.textColor,
    this.width,
    this.height,
    this.padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
    this.borderRadius = const BorderRadius.all(Radius.circular(8)),
    this.fontSize = 16,
    this.fontWeight = FontWeight.w600,
  });
}

// Builder для кнопки
class CustomButtonBuilder {
  late String _label;
  late VoidCallback _onPressed;
  Color? _backgroundColor;
  Color? _textColor;
  double? _width;
  double? _height;
  EdgeInsets _padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 12);
  BorderRadius _borderRadius = const BorderRadius.all(Radius.circular(8));
  double _fontSize = 16;
  FontWeight _fontWeight = FontWeight.w600;
  
  CustomButtonBuilder label(String label) {
    _label = label;
    return this;
  }
  
  CustomButtonBuilder onPressed(VoidCallback callback) {
    _onPressed = callback;
    return this;
  }
  
  CustomButtonBuilder backgroundColor(Color color) {
    _backgroundColor = color;
    return this;
  }
  
  CustomButtonBuilder textColor(Color color) {
    _textColor = color;
    return this;
  }
  
  CustomButtonBuilder size(double width, double height) {
    _width = width;
    _height = height;
    return this;
  }
  
  CustomButtonBuilder padding(EdgeInsets padding) {
    _padding = padding;
    return this;
  }
  
  CustomButtonBuilder borderRadius(BorderRadius radius) {
    _borderRadius = radius;
    return this;
  }
  
  CustomButtonBuilder fontSize(double size) {
    _fontSize = size;
    return this;
  }
  
  ButtonConfig build() {
    return ButtonConfig(
      label: _label,
      onPressed: _onPressed,
      backgroundColor: _backgroundColor,
      textColor: _textColor,
      width: _width,
      height: _height,
      padding: _padding,
      borderRadius: _borderRadius,
      fontSize: _fontSize,
      fontWeight: _fontWeight,
    );
  }
}

// Использование в Flutter
final buttonConfig = CustomButtonBuilder()
  .label('Click me')
  .onPressed(() => print('Clicked!'))
  .backgroundColor(Colors.blue)
  .textColor(Colors.white)
  .size(200, 50)
  .fontSize(18)
  .build();

Преимущества Builder

  1. Читаемость — понятно, что делается на каждом шаге
  2. Гибкость — легко добавлять новые опции
  3. Валидация — можно проверять данные в build()
  4. Повторное использование — builder можно переиспользовать
  5. Неизменяемость — создаёт immutable объекты

Builder vs Конструктор с параметрами

Конструктор — когда мало параметров (до 3-4)

User(name: 'John', email: 'john@example.com')

Builder — когда много параметров или сложная логика

UserBuilder()
  .name('John')
  .email('john@example.com')
  .phone('+123')
  .address('Some Address')
  .build()

В Dart часто используют именованные параметры вместо Builder для простых случаев, но Builder остаётся полезен для более сложных объектов с валидацией.

Builder паттерн — это классическое решение для создания сложных объектов с множеством параметров.

Что такое паттерн Builder? | PrepBro