Обзор шаблона проектирования Singleton и его реализации в Dart и Flutter

Прежде всего, я хотел бы поблагодарить всех вас за поддержку после публикации вводной статьи к этой серии. Честно говоря, я не ожидал, что такое количество людей не только заинтересуется созданием мобильных приложений с использованием Flutter, но и захочет узнать больше о самом языке Dart, шаблонах проектирования ООП и их применении, архитектуре кода или разработке программного обеспечения в Общее. Это побудило меня сразу погрузиться в исследования, кодирование и, следовательно, я представляю вам первый шаблон проектирования в этой серии - синглтон.

Оглавление

  • Что такое синглтон?
  • Анализ
  • Реализация
  • Другие статьи из этой серии
  • Ваш вклад

Что такое синглтон?

Синглтон - это творческий шаблон проектирования, который гарантирует, что у класса есть только один экземпляр, а также обеспечивает глобальную точку доступа к нему. Мотивация этого паттерна изложена в Книге GoF:

Для некоторых классов важно иметь только один экземпляр. Хотя в системе может быть много принтеров, диспетчер очереди печати должен быть только один. Должна быть только одна файловая система и один оконный менеджер ...

Основная идея этого шаблона - сделать класс ответственным за отслеживание своего единственного экземпляра. Синглтон считается одним из простейших шаблонов проектирования, но в нем также легко ошибиться, если вы не будете осторожны. Итак, перейдем к анализу и проясним детали синглтона и его реализации.

Анализ

Для начала я должен упомянуть, что в каждой статье этой серии вы найдете несколько диаграмм классов UML. Если вы не знакомы с диаграммами классов и их обозначениями, я настоятельно рекомендую вам прочитать эту справку.

Диаграмма классов и базовая структура

Общий подход к реализации Singleton представлен на диаграмме классов ниже:

  • Singleton класс содержит статическое свойство instance, которое является ссылкой на сам экземпляр класса (эта связь представлена ​​как ссылка ассоциации из класса Синглтон себе);
  • Этот экземпляр доступен только через статический метод getInstance ();
  • Конструктор класса помечен как частный (он может быть защищен в других реализациях), чтобы гарантировать, что класс не может быть создан извне.

Применимость

Синглтон можно использовать в тех случаях, когда создание экземпляра класса дорого, например. создание экземпляра класса требует загрузки большого количества данных из внешних источников. Кроме того, шаблон помогает, когда вам нужно снова и снова обращаться к одному и тому же объекту в коде, например. logger (эта проблема обычно решается путем применения другого шаблона проектирования - внедрения зависимостей, но это тема будущего 😊). Синглтон также можно использовать, когда требуется какой-то уровень кеширования - класс синглтона может проверять и управлять кешем по запросу экземпляра.

Общие мысли и опасности

  • При разработке синглтона следует учитывать ленивое построение - экземпляр класса должен создаваться только тогда, когда он впервые нужен;
  • Как правило, для построения класса Singleton не требуются параметры. Если для дизайна вашего класса требуется параметр, это может привести к созданию какого-то другого объекта на основе этого параметра - тогда можно ли этот класс называть синглтоном? Некоторые ресурсы утверждают, что это действительный подход, но у меня другое мнение;
  • Безопасность потоков - вы должны знать о синглтонах в многопоточных приложениях. Если они содержат какие-то изменяемые данные, это может привести к неожиданным результатам, поэтому следует рассмотреть механизм синхронизации.
    Поскольку в этой серии статей мы говорим о языке программирования Dart, вы должны знать, что Dart - это однопоточный язык программирования, и его код выполняется в небольшом изолированном пространстве на машине, называемом изолированным. Следовательно, вам не следует беспокоиться о безопасности потоков при реализации синглтонов в Dart, если вы сами не создаете новый отдельный изолятор из кода. Если вы не знакомы с этой темой, я настоятельно рекомендую вам посмотреть это видео о изолятах и ​​циклах событий в Dart и Flutter.
  • В некоторых случаях шаблон проектирования Singleton считается анти-шаблоном. Это потому, что он нарушает один (на самом деле, несколько, но этот пример, на мой взгляд, лучший) из принципов SOLID - принцип единой ответственности. Помимо основной ответственности класса Singleton, он также должен управлять временем жизни своего экземпляра, что является отдельной проблемой. Кроме того, использование синглтонов затрудняет модульное тестирование кода, поскольку имитировать синглетон невозможно, если вы не предоставите какой-либо интерфейс, который служит его типом.

Реализация

Мы будем использовать шаблон проектирования Singleton, чтобы сохранить состояние нашего примера Singleton в приложении Flutter Design Patterns. Чтобы упростить задачу, в состоянии сохраняется только одно текстовое свойство. Само состояние примера реализуется тремя разными способами:

  • Использование шаблона проектирования Singleton, который реализован по определению;
  • Использование шаблона проектирования Singleton, реализованного с использованием возможностей языка Dart;
  • Без использования синглтона вообще.

ExampleStateBase

Поскольку состояние примера реализовано несколькими разными способами, была создана его абстракция для повторного использования во всех реализациях. Следовательно, класс ExampleStateBase предоставляет это абстрактное состояние:

Как уже упоминалось, состояние примера состоит только из одного свойства String stateText и его начального значения initialText. Свойства stateText ant initialText помечены как protected - необходимо сделать эти свойства доступными только для тех классов, которые расширяют ExampleStateBase класс. Однако Dart не поддерживает видимость protected так же, как некоторые из вас могли ожидать, что она будет исходить от другого языка ООП, такого как C # или Java - мы можем только аннотировать эти свойства как protected, но это скорее напоминание для разработчика не использовать их за пределами области действия класса (в этом случае редактор кода Visual Studio даже показывает предупреждение). Кроме того, ExampleStateBase предоставляет методы для работы с stateText.

Реализация синглтона по определению

На диаграмме классов ниже представлены конкретные классы приложения Flutter Design Patterns, которые по определению реализуют шаблон проектирования Singleton.

  • ExampleStateByDefinition расширяет класс ExampleStateBase для получения доступа к состоянию (в данном случае, stateText и initialText) и его методы.
  • ExampleStateByDefinition реализует шаблон проектирования Singleton и обрабатывает создание экземпляра. Экземпляр доступен только через статический метод getState ().

Код ExampleStateByDefinition:

Реализация синглтона с использованием магии Дарта

Класс ExampleState реализует шаблон проектирования Singleton «Путь Dart»:

Сравнивая этот код с предыдущей реализацией, вы могли заметить, что статический метод getState () отсутствует - ну, он просто больше не нужен! Язык Dart предоставляет конструктор фабрики. Он используется для реализации конструктора, который не всегда создает новый экземпляр своего класса - это красивый и элегантный способ реализовать класс как синглтон, не так ли? Теперь вы можете создать экземпляр класса ExampleState, вызвав его конструктор фабрики таким же образом, как если бы вы это делали, вызывая конструктор по умолчанию - конструктор фабрики создаст новый экземпляр или вернет существующий, если он уже был инициирован.

ExampleStateWithoutSingleton

Просто простая реализация класса состояния, не беспокоясь о синглтоне или каких-либо других модных шаблонах проектирования.

Пример

Прежде всего, подготавливается файл разметки, который предоставляется как описание шаблона:

В самом примере используются все три различных реализации состояния:

Реализации синглтона (ExampleStateByDefinition и ExampleState) создают новый объект состояния только при первом создании виджета SingletonExample, но ExampleStateWithoutSingleton создается при каждом создании виджета SingletonExample. Это поведение можно было заметить, изменив состояние и заставив виджет примера перестроиться, например переключением вкладок:

Или перейдя в главное меню и обратно:

Как видите, состояние, которое реализовано как синглтон, остается неизменным, поскольку новый экземпляр класса состояния не создается при перестроении виджета в примере.

Все изменения кода для шаблона проектирования Singleton и его пример реализации можно найти здесь.

Другие статьи из этой серии

Ваш вклад

👏 Нажмите кнопку хлопка ниже, чтобы выразить свою поддержку и побудить меня писать лучше!
💬 Оставьте отзыв на эту статью, поделившись своими мыслями, комментариями или пожеланиями относительно серии.
📢 Поделитесь этой статьей со своими друзья, коллеги в социальных сетях.
➕ Подписывайтесь на меня на Medium.
⭐ Пометьте репозиторий Github.