Сравнение способов создания синглетонов в Dart
Я читаю эти посты:
- Как вы строите синглтон в дартс?
- Как реализовать шаблон Singleton в Dart, используя фабричные конструкторы?
- Структуры объектов в дротике
У меня возникли небольшие проблемы с пониманием разницы между следующими способами создания синглетонов:
1. Фабричный конструктор
class SingletonOne {
SingletonOne._privateConstructor();
static final SingletonOne _instance = SingletonOne._privateConstructor();
factory SingletonOne(){
return _instance;
}
}
2. Статическое поле с геттером
class SingletonTwo {
SingletonTwo._privateConstructor();
static final SingletonTwo _instance = SingletonTwo._privateConstructor();
static SingletonTwo get instance { return _instance;}
}
3. Статическое поле
class SingletonThree {
SingletonThree._privateConstructor();
static final SingletonThree instance = SingletonThree._privateConstructor();
}
Они создаются следующим образом:
SingletonOne one = SingletonOne();
SingletonTwo two = SingletonTwo.instance;
SingletonThree three = SingletonThree.instance;
Вопросы
Гюнтер Цохбауэр сказал по этому вопросу:
Нет необходимости использовать конструктор фабрики. Конструктор фабрики был удобен, когда новый еще не был обязательным, потому что тогда он
new MyClass()
работал для классов, где конструктор каждый раз возвращал новый экземпляр или когда класс возвращал кэшированный экземпляр. Вы не должны были знать, как и когда объект был создан.
Я не понимаю как new
необязательность теперь делает конструктор фабрики ненужным. Прежде чем ты не мог сделать что-то вроде SingletonTwo
или же SingletonThree
выше?
Вы также можете изменить
static final DbHelper _db = new DbHelper._constr();
вstatic final DbHelper singleton = new DbHelper._constr();
и удалите одиночный геттер, который я предложил в своем ответе. Это зависит от вашего варианта использования. Возможно, вы не сможете использовать инициализатор поля, если вам нужны дополнительные значения конфигурации для создания экземпляра. В вашем примере этого было бы достаточно, хотя.
Каковы варианты использования для каждого из приведенных выше шаблонов синглтона (SingletonOne, SingletonTwo и SingletonThree)? Было бы полезно увидеть пример для каждого. Разве фабричный шаблон не будет полезен, если вы хотите скрыть тот факт, что класс был одноэлементным (как описано здесь)?
2 ответа
Как сказал в комментариях Гюнтер Цохбауэр, каждый из трех перечисленных вами способов создания синглетонов одинаков. Используйте ваши личные предпочтения, чтобы выбрать один.
Я собираюсь добавить некоторые дополнительные заметки:
SingletonOne
когда создается экземпляр выглядит как любой другой класс. Таким образом, вы можете использовать это, если хотите скрыть тот факт, что это синглтон (и оставить опцию, чтобы он не был синглтоном в будущем). Вы также можете передать аргументы в конструкторе.SingletonTwo
позволит вам сделать другую работу, прежде чем возвращать экземпляр.SingletonThree
самый короткий, и короткий чистый код желателен в моей книге, при прочих равных условиях.
Я отправляю это как предварительный ответ и хотел бы получить отзыв. Другие полные / лучшие ответы также приветствуются.
Поскольку Dart допускает переменные корневого уровня, можно получить отличную ленивую загрузку синглтона:
final store = _Store();
class _Store {
//
}
Ограничения
Как и три других ваших примера, это не сработает, если вам нужно асинхронное построение. Кроме того, как и SingletonTwo и SingletonThree, вы не можете передавать какие-либо аргументы из вызывающей области.
Для синглтона, который требует асинхронной конструкции и аргументов, я бы использовал что-то вроде этого:
class StoreService {
static StoreService? _instance;
StoreService._() {}
static Future<StoreService> create() async {
// we can await things here
if (_instance == null) {
_instance = StoreService._();
}
return _instance!;
}
}