Что такое паттерн Фабричный метод?

«Что такое паттерн Фабричный метод?» — вопрос из категории Паттерны, который задают на 44% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Фабричный метод — это порождающий паттерн, который определяет интерфейс (абстрактный метод) для создания объекта в базовом классе, но позволяет подклассам изменять тип создаваемого объекта. Таким образом, логика работы с продуктом остается в базовом классе, а конкретный класс продукта определяется наследниками.

Зачем он нужен? Чтобы отвязать основной код от конкретных классов создаваемых объектов. Это особенно полезно, когда у вас есть общая структура (виджет, диалог, обработчик), но конечная реализация может различаться в зависимости от контекста (платформа, настройки пользователя).

Пример на Dart/Flutter: Создаем диалоговое окно, внешний вид которого (кнопки) зависит от платформы.

// Абстрактный класс продукта - кнопка
abstract class DialogButton {
  String get label;
  void onPressed();
  Widget render(); // Возвращает Flutter-виджет
}

// Конкретные продукты
class MaterialDialogButton implements DialogButton {
  @override
  final String label;
  final VoidCallback onPressed;

  MaterialDialogButton({required this.label, required this.onPressed});

  @override
  Widget render() {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(label),
    );
  }
}

class CupertinoDialogButton implements DialogButton {
  @override
  final String label;
  final VoidCallback onPressed;

  CupertinoDialogButton({required this.label, required this.onPressed});

  @override
  Widget render() {
    return CupertinoButton(
      onPressed: onPressed,
      child: Text(label),
    );
  }
}

// Базовый класс Creator с фабричным методом
abstract class AlertDialog {
  // Фабричный метод - subclasses должны его реализовать
  DialogButton createConfirmButton();
  DialogButton createCancelButton();

  // Общая логика построения диалога, использующая фабричный метод
  Widget build(BuildContext context) {
    final confirmButton = createConfirmButton();
    final cancelButton = createCancelButton();

    // Здесь общая логика компоновки виджетов диалога...
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        // ... содержимое диалога ...
        Row(
          children: [
            cancelButton.render(),
            confirmButton.render(),
          ],
        ),
      ],
    );
  }
}

// Конкретные создатели (Concrete Creators)
class MaterialAlertDialog extends AlertDialog {
  final VoidCallback onConfirm;
  final VoidCallback onCancel;

  MaterialAlertDialog({required this.onConfirm, required this.onCancel});

  @override
  DialogButton createConfirmButton() {
    return MaterialDialogButton(
      label: 'OK',
      onPressed: onConfirm,
    );
  }

  @override
  DialogButton createCancelButton() {
    return MaterialDialogButton(
      label: 'Cancel',
      onPressed: onCancel,
    );
  }
}

class CupertinoAlertDialog extends AlertDialog {
  final VoidCallback onConfirm;
  final VoidCallback onCancel;

  CupertinoAlertDialog({required this.onConfirm, required this.onCancel});

  @override
  DialogButton createConfirmButton() {
    return CupertinoDialogButton(
      label: 'OK',
      onPressed: onConfirm,
    );
  }

  @override
  DialogButton createCancelButton() {
    return CupertinoDialogButton(
      label: 'Cancel',
      onPressed: onCancel,
    );
  }
}

// Использование:
// Widget build(BuildContext context) {
//   final dialog = Platform.isIOS
//       ? CupertinoAlertDialog(onConfirm: _save, onCancel: _close)
//       : MaterialAlertDialog(onConfirm: _save, onCancel: _close);
//   return dialog.build(context);
// }

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

  • Избавляет от жесткой привязки к конкретным классам продуктов в основном коде.
  • Принцип единой ответственности: код создания продукта переносится в одно место (подклассы).
  • Принцип открытости/закрытости: легко добавить новый тип продукта, создав новый подкласс, не трогая существующий код.

Отличие от Абстрактной фабрики: Фабричный метод создает один тип продукта, а Абстрактная фабрика — целое семейство связанных продуктов.