Нетерпеливые флаттера против ленивых одиночек. Загрузка и создание экземпляров

Я понимаю разницу между нетерпеливыми и ленивыми синглтонами: нетерпеливый экземпляр создается при первой загрузке, а ленивый создается при первом использовании (называемый метод).

Теперь, чтобы полностью понять разницу, мы должны знать, когда происходит загрузка. Согласно этой статье, это происходит на этапе запуска Dart VM. Непосредственно перед созданием и запуском фазы Dart Isolate при вызове метода main.

Вопрос в следующем: когда мы вызываем синглтон из main

void main() async{
  await MyService().execute();
  runApp( MainApp());
}

разницы между нетерпеливым и ленивым практически нет. Я прав?

Обновлять. Реализации нетерпеливых (ранних) и ленивых синглтонов.

Жаждущий:

class MyService{
  MyService._();
  static final _instance = MyService._();
  factory MyService() => _instance;
} 

Ленивый:

class MyService{
  MyService._();
  static MyService _instance;
  factory MyService() => _instance ??= MyService();
} 

Обновление 2.

Как пояснил jamesdin в комментариях, Dart имеет ленивую инициализацию статических переменных, и поэтому первый подход предпочтительнее, поскольку он немного короче и не требует дальнейших проверок на ноль.

между обоими подходами определенно есть разница: представьте, что «вы реализовали Eager Singleton = Early Singleton и никогда его не использовали», что приводит к (одному ненужному объекту в оперативной памяти), который является экземпляром.

A-E 09.06.2024 13:59

Все глобальные переменные и переменные static в Dart инициализируются лениво, поэтому я не понимаю, что вы подразумеваете под нетерпеливым синглтоном. Я также не понимаю, какое отношение имеет статья, на которую вы ссылаетесь, к синглтонам. Можете ли вы уточнить?

jamesdlin 09.06.2024 16:46

@AE Полностью согласен, но вряд ли могу себе представить сценарий, когда синглтон не будет использоваться. Сбой приложения? Закрыто пользователем? В обоих случаях об оперативной памяти можно не беспокоиться.

Yuriy N. 09.06.2024 17:27

@jamesdlin Я обновил вопрос, чтобы уточнить, что я имею в виду под нетерпеливым и ленивым. Статья не имеет никакого отношения конкретно к синглтонам. Это единственное место, которое я нашел, где указывается, когда классы загружаются в приложение Dart. Можете ли вы сказать, что приведенный выше код практически идентичен, поскольку нетерпеливые все равно будут инициализироваться лениво?

Yuriy N. 09.06.2024 17:40

Ваша «ленивая» версия нелегальна. Даже если вы исправите объявление в static MyService? _instance;, предполагая, что ничто другое в библиотеке не обращается к MyService._instance напрямую и не проходит только через конструктор factory, не будет никакой разницы в том, когда объект будет инициализирован. Как я уже говорил, все глобальные переменные и static уже ленивы. То есть они будут инициализированы при первом обращении к ним. Последний метод излишне многословен и усложняет необходимость проверки null при каждом использовании _instance.

jamesdlin 09.06.2024 17:43

@Джеймсдлин. Верно. Зафиксированный. (проблема с быстрой копипастой). Большое спасибо за разъяснения. Я не думаю, что эта информация широко известна. Например, на этот вопрос stackoverflow.com/questions/12649573/… есть ответ с 87 голосами «за» и реализация, аналогичная приведенной выше (с геттером вместо фабрики). В любом случае, мой вопрос больше не имеет смысла. ))) Еще раз спасибо.

Yuriy N. 09.06.2024 18:13

@jamesdin Хотите опубликовать то, что вы прокомментировали, в качестве ответа? Я думаю, что многим людям не хватает этих знаний.

Yuriy N. 09.06.2024 18:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Реализация Singleton почти всегда включает глобальные переменные или static, но глобальные и static переменные уже инициализируются лениво при первом обращении к ним. Из тура Dart Language:

Переменные верхнего уровня и класса инициализируются лениво; код инициализации запускается при первом использовании переменной.

Итак, учитывая ваш пример:

Жаждущий:

class MyService{
  MyService._();
  static final _instance = MyService._();
  factory MyService() => _instance;
} 

Ленивый:

class MyService{
  MyService._();
  static MyService? _instance;
  factory MyService() => _instance ??= MyService();
} 

не будет никакой разницы, когда MyService будет инициализирован (при условии, что все остальное использует конструктор MyService фабрики и не имеет прямого доступа к MyService._instance). В обоих случаях _instance будет лениво инициализирован при первом явном вызове конструктора фабрики после ввода main(). Ни одна из версий на самом деле не рвется.

«Ленивая» версия излишне многословна и добавляет дополнительную проверку на ноль. Как написано, это бесполезно. Однако эта практика может быть полезна в ситуациях, когда вы можете захотеть инициализировать синглтон чем-то другим:

import 'package:meta/meta.dart';

class MyService{
  MyService._();
  static MyService? _instance;
  factory MyService() => _instance ??= MyService();

  @visibleForTesting
  factory MyService.test(MyService service) {
    _instance = service;
  }
} 

и тогда тесты могут явно использовать MyService.test для инициализации синглтона поддельной или имитационной реализации.

> «Нетерпеливая» версия излишне многословна и добавляет дополнительную проверку на ноль. Опечатка: вместо этого должно быть «лениво».

Yuriy N. 09.06.2024 19:37

@YuriyN. Ой, да. Зафиксированный.

jamesdlin 09.06.2024 19:54

Другие вопросы по теме