Ответ
Фабричный метод — это порождающий паттерн, который определяет интерфейс (абстрактный метод) для создания объекта в базовом классе, но позволяет подклассам изменять тип создаваемого объекта. Таким образом, логика работы с продуктом остается в базовом классе, а конкретный класс продукта определяется наследниками.
Зачем он нужен? Чтобы отвязать основной код от конкретных классов создаваемых объектов. Это особенно полезно, когда у вас есть общая структура (виджет, диалог, обработчик), но конечная реализация может различаться в зависимости от контекста (платформа, настройки пользователя).
Пример на 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);
// }
Преимущества:
- Избавляет от жесткой привязки к конкретным классам продуктов в основном коде.
- Принцип единой ответственности: код создания продукта переносится в одно место (подклассы).
- Принцип открытости/закрытости: легко добавить новый тип продукта, создав новый подкласс, не трогая существующий код.
Отличие от Абстрактной фабрики: Фабричный метод создает один тип продукта, а Абстрактная фабрика — целое семейство связанных продуктов.