В предыдущем посте мы узнали о том, что такое паттерн Observer (Наблюдатель) и как его применять в Dart-коде. Сегодня продолжим обсуждение поведенческих шаблонов проектирования и поговорим о шаблоне Mediator (Посредник).
Представьте ситуацию — сначала у вас в работе простой проект, в нем буквально несколько простых функций, каждая из которых особо не пересекается с другими. Но со временем ваш проект разрастается, количество классов становится все больше, их связи между собой все сложнее. В таком случае рано или поздно в коде воцарится хаос, в котором будет крайне сложно разобраться всем членам команды. Именно тут отлично впишется паттерн Посредник.
Посредник подразумевает создание некоторого класса, который берет на себя роль связующего звена между другими объектами. При его внедрении все взаимодействие объектов проходит только через него, непосредственное общение между объектами минимизируется.
✈️Для простоты понимания представим посредником авиационную диспетчерскую вышку, а все остальные объекты в коде — самолетами. Самолеты не общаются друг с другом, так как это общение может привести к хаосу в полете. Всеми вопросами связи занимается именно диспетчер.
А с чем сравнить посредника во Flutter-приложении? Представим, что нам надо на трех разных экранах приложения сделать отображение значения счетчика. При этом счетчик должен быть общим.
Без посредника на каждом экране пришлось бы вызывать обновление счетчика не только на текущей странице, но и на двух других. Таким образом, все три экрана были бы связаны.
С посредником можно было бы создать класс CounterMediator, который возьмет на себя всю основную логику — он хранит общее значение счетчика, дает доступ к методам обновления этого значения и уведомляет слушателей.
class CounterMediator {
int _counter = 0;
final List<Function(int)> _listeners = [];
/// Значение счетчика
int get counter => _counter;
/// Добавляет слушателя, который будет уведомлен при изменении счетчика
void addListener(Function(int) listener) {
_listeners.add(listener);
}
/// Изменяет значение счетчика и уведомляет всех слушателей
void increment() {
_counter++;
for (final listener in _listeners) {
listener(_counter);
}
}
}В таком случае каждый из экранов получил бы простую обособленную реализацию. Экран принимает экземпляр посредника-счетчика, слушает и отображает значение счетчика, а также вызывает метод обновления. В таком случае значения на экранах обновляются без связи друг с другом.
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key, required this.mediator});
final CounterMediator mediator;
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _counter = 0;
@override
void initState() {
super.initState();
// Подписываемся на изменения посредника-счетчика
widget.mediator.addListener((newCounter) {
setState(() => _counter = newCounter);
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Счетчик: $_counter'),
ElevatedButton(
onPressed: widget.mediator
.increment, // Вызываем метод увеличения значения счетчика
child: const Text('+'),
),
],
);
}
}
❤️ – если пост был полезен
