Если вы занимаетесь программированием на Flutter, то наверняка сталкивались с задачами, которые можно было бы решить более эффективно и легко, используя уже проверенные практиками решения. В этом и помогают паттерны проектирования на Dart — шаблоны, которые разработчики применяют для решения часто встречающихся проблем. В двух статьях команда Mad Brains рассмотрит 16 паттернов проектирования на Dart, как они могут быть использованы для улучшения качества кода и повышения эффективности разработки.   Паттерн Singleton (Одиночка) является порождающим паттерном проектирования.Цель паттерна заключается в том, чтобы у класса мог быть только единственный экземпляр во всей программе и к нему была предоставлена глобальная точка доступа. Реализация: сокрытие конструктора класса и создание статического метода / поля / геттера, предоставляющего доступ к экземпляру класса. Пример кода Дает гарантию, что в программе может быть только один экземпляр класса; Предоставляет глобальную точку доступа к экземпляру. Имеет проблемы с потоками в многопоточных языках; Требует особой тактики тестирования при юнит-тестировании. Паттерн Abstract factory (Абстрактная фабрика) является порождающим паттерном проектирования.Целью паттерна является возможность создания семейства связанных объектов, не привязываясь к их конкретным классам. Реализация: Выделение общих интерфейсов для семейств объектов. Определение интерфейса абстрактной фабрики, имеющего методы для создания каждого из типов семейств объектов. Создание для каждого семейства объектов конкретного класса фабрики, реализующего интерфейс абстрактной фабрики. Пример кода Реализует Принцип открытости/закрытости; Упрощает замену и добавление новых семейств продуктов; Гарантирует сочетаемость продуктов; Избавляет клиентский код от привязки к конкретным классам продуктов. Усложняет код программы из-за введения множества дополнительных классов. Паттерн Adapter (Wrapper, Адаптер) является структурным паттерном проектирования.Цель паттерна заключается в обеспечении возможности совместной работы объектов с несовместимыми интерфейсами. Реализация: Создание класса адаптера, реализующего интерфейс, который ожидает клиент. Поместить в адаптер существующий класс с нужным функционалом, но не совместимым с интерфейсом, ожидаемом в клиенте. Реализовать в адаптере все методы интерфейса, который ожидает клиент, делегируя всю работу помещенному в адаптер классу. Пример кода Позволяет повторно использовать имеющийся объект, адаптируя его несовместимый интерфейс, отделяя и скрывая от клиента подробности преобразования. Усложняет код программы из-за введения дополнительных классов. Паттерн Decorator (Декоратор, Обертка) является структурным паттерном проектирования.Цель паттерна заключается в предоставлении возможности динамического добавления объектам новой функциональности, оборачивая их в классы-обёртки. Реализация: Создание интерфейса компонента, описывающего общие методы как для конкретного компонента, так и для его декораторов. Создание класса конкретного компонента, содержащего основную бизнес-логику. Конкретный компонент должен следовать интерфейсу компонента. Создание базового класса для декораторов. Он должен хранить в себе ссылку на вложенный компонент. Базовый декоратор должен следовать тому же интерфейсу компонента, что и конкретный компонент. Создание классов конкретных декораторов, наследующих базовый. Конкретный декоратор должен выполнять свою добавочную функцию до или после вызова этой же функции обёрнутого объекта. Пример кода Позволяет динамически добавлять одну или несколько новых обязанностей; Имеет большую гибкость, чем у наследования. Множество мелких классов. Если эта статья кажется вам простой, то огонь — приходите к нам работать! У нас открыта вакансия Flutter-разработчика, подробности можно узнать на сайте Mad Brains в разделе «Карьера».    Паттерн Command (Команда) является поведенческим паттерном проектирования.Цель паттерна заключается в представлении действий как объектов, заключающих в себе само действие и его параметры, что позволяет сохранять историю действий, ставить их в очередь, поддерживать их отмену и повтор. С паттерном Команда всегда связаны четыре термина: Команды (Command) - классы, представляющие действие как объект. Получатель (Приемник, Receiver) - класс, содержащий реализацию действий, команды делегируют ему свои действия, вызывая его методы. Отправитель (Invoker) - класс, вызывающий команды. Работает с командами только через их общий интерфейс, не зная ничего о конкретных командах. Отправитель может вести учёт и запись выполненных команд. Клиент (Client) - создает объекты конкретных команд и связывает их с отправителем для их выполнения. Реализация: Создание общего интерфейса для команд, определение в нем метода вызова команды. Создание классов конкретных команд. В каждом классе должно быть поле, хранящее объект-получатель, которому команда будет делегировать свою работу. При необходимости команда должна получать через конструктор и хранить в себе поля параметров, необходимых для вызова методов получателя. Добавление в класс отправитель метода для вызова команды. Отправитель может как хранить в себе команды для их вызова, так и принимать команду в методе для ее вызова, либо иметь сеттер для поля команды. Создание в клиенте объекта получателя, объектов команд и их связь с отправителем. Пример кода Реализует Принцип открытости/закрытости; Позволяет реализовать отмену и повтор операций, хранить историю их выполнения; Позволяет собирать сложные команды из простых; Позволяет реализовать отложенный запуск операций (ставить их в очередь). Усложняет код из-за необходимсоти создания множества дополнительных классов. Паттерн Visitor (Посетитель) является поведенческим паттерном проектирования.Цель паттерна заключается в предоставлении возможности добавлять в программу новые операции над объектами других классов без необходимости изменения этих классов. Реализация: Создание интерфейса посетителя и объявление в нем методов посещения visit()  для каждого класса, над которым будет выполняться операция "посещения". Реализация метода принятия accept(Visitor visitor)  посетителя в интерфейсе или базовом классе иерархии элементов, над которыми будет производиться операция "посещения".Иерархия элементов должна знать только о базовом интерфейсе посетителей, в то время как посетители будут знать о всех подклассах иерархии элементов. Реализация метода принятия accept(Visitor visitor)  посетителя во всех конкретных элементах иерархии. Каждый конкретный элемент должен делегировать выполнение метода accept(Visitor visitor)  тому методу посетителя, в котором тип параметра совпадает с текущим классом элемента. Создание новых конкретных посетителей для каждого нового действия над элементами иерархии. Конкретный посетитель должен реализовывать все методы интерфейса посетителей, выполняя требуемое действие. Клиенты создают объекты посетителей и передают их каждому элементу, использую метод принятия accept(Visitor visitor) . Пример кода Упрощает добавление новых операций над элементами; Объединяет родственные операции в классе Visitor ; Дает возможность запоминать состояние по мере обхода элементов. Затрудняет добавление новых классов в иерархию, так как каждый раз придется обновлять интерфейс посетителя и его конкретные подклассы. Если вам интересно развиваться во Flutter, хорошая новость: у нас открыта вакансия Flutter-разработчика, подробности можно узнать на сайте Mad Brains в разделе «Карьера». Вторая часть статьи выйдет уже на следующей неделе. В комментариях пишите, что было полезно, и что хотели бы узнать о технологии подробнее.   IT-компания