Le modèle singleton garantit qu'une seule instance d'une classe est créée. Comment puis-je construire cela dans Dart?
Grâce aux constructeurs factory de Dart , il est facile de créer un singleton:
class Singleton {
static final Singleton _singleton = new Singleton._internal();
factory Singleton() {
return _singleton;
}
Singleton._internal();
}
Vous pouvez le construire avec new
main() {
var s1 = new Singleton();
var s2 = new Singleton();
print(identical(s1, s2)); // true
print(s1 == s2); // true
}
Je ne trouve pas cela très intuitif de lire new Singleton (). Vous devez lire la documentation pour savoir que new ne crée pas réellement une nouvelle instance, comme il le ferait normalement.
Voici une autre façon de faire des singletons (essentiellement ce que Andrew a dit ci-dessus).
lib/thing.Dart
library thing;
final Thing thing = new Thing._private();
class Thing {
Thing._private() { print('#2'); }
foo() {
print('#3');
}
}
main.Dart
import 'package:thing/thing.Dart';
main() {
print('#1');
thing.foo();
}
Notez que le singleton n’est créé que lors du premier appel du getter en raison de l’initialisation lente de Dart.
Si vous préférez, vous pouvez également implémenter des singletons en tant que getter statique dans la classe singleton. c'est-à-dire Thing.singleton, au lieu d'un getter de premier niveau.
Lisez également le point de vue de Bob Nystrom sur singletons de son livre de modèles de programmation de jeux .
Qu'en est-il de l'utilisation d'une variable globale dans votre bibliothèque, comme ceci?
single.Dart
:
library singleton;
var Singleton = new Impl();
class Impl {
int i;
}
main.Dart
:
import 'single.Dart';
void main() {
var a = Singleton;
var b = Singleton;
a.i = 2;
print(b.i);
}
Ou est-ce mal vu?
Le modèle singleton est nécessaire en Java, où le concept de globals n'existe pas, mais il semble que vous ne devriez pas avoir à faire tout le chemin dans Dart.
Voici une comparaison de plusieurs façons différentes de créer un singleton dans Dart.
class SingletonOne {
SingletonOne._privateConstructor();
static final SingletonOne _instance = SingletonOne._privateConstructor();
factory SingletonOne(){
return _instance;
}
}
class SingletonTwo {
SingletonTwo._privateConstructor();
static final SingletonTwo _instance = SingletonTwo._privateConstructor();
static SingletonTwo get instance { return _instance;}
}
class SingletonThree {
SingletonThree._privateConstructor();
static final SingletonThree instance = SingletonThree._privateConstructor();
}
Les singletons ci-dessus sont instanciés comme ceci:
SingletonOne one = SingletonOne();
SingletonTwo two = SingletonTwo.instance;
SingletonThree three = SingletonThree.instance;
Note:
À l’origine, j’avais posé cette question sous forme de question , mais j’ai découvert que toutes les méthodes ci-dessus étaient valables et que le choix dépendait en grande partie de vos préférences personnelles.
Voici un autre moyen possible:
void main() {
var s1 = Singleton.instance;
s1.somedata = 123;
var s2 = Singleton.instance;
print(s2.somedata); // 123
print(identical(s1, s2)); // true
print(s1 == s2); // true
//var s3 = new Singleton(); //produces a warning re missing default constructor and breaks on execution
}
class Singleton {
static final Singleton _singleton = new Singleton._internal();
Singleton._internal();
static Singleton get instance => _singleton;
var somedata;
}
Dart singleton par const constructeur & factory
class Singleton {
factory Singleton() =>
const Singleton._internal_();
const Singleton._internal_();
}
void main() {
print(new Singleton() == new Singleton());
print(identical(new Singleton() , new Singleton()));
}
Singleton qui ne peut pas changer l'objet après l'instance
class User {
final int age;
final String name;
User({
this.name,
this.age
});
static User _instance;
static User getInstance({name, age}) {
if(_instance == null) {
_instance = User(name: name, idade: age);
return _instance;
}
return _instance;
}
}
print(User.getInstance(name: "baidu", age: 24).age); //24
print(User.getInstance(name: "baidu 2").name); // is not changed //baidu
print(User.getInstance()); // {name: "baidu": age 24}
Voici un exemple concis qui combine les autres solutions. L'accès au singleton peut être fait par:
singleton
qui pointe vers l'instance.Singleton.instance
commun.Remarque: Vous ne devez implémenter qu'une des trois options afin que le code utilisant le singleton soit cohérent.
Singleton get singleton => Singleton.instance;
ComplexSingleton get complexSingleton => ComplexSingleton._instance;
class Singleton {
static final Singleton instance = Singleton._private();
Singleton._private();
factory Singleton() => instance;
}
class ComplexSingleton {
static ComplexSingleton _instance;
static ComplexSingleton get instance => _instance;
static void init(arg) => _instance ??= ComplexSingleton._init(arg);
final property;
ComplexSingleton._init(this.property);
factory ComplexSingleton() => _instance;
}
Si vous devez effectuer une initialisation complexe, il vous suffira de le faire avant d'utiliser l'instance ultérieurement dans le programme.
Exemple
void main() {
print(identical(singleton, Singleton.instance)); // true
print(identical(singleton, Singleton())); // true
print(complexSingleton == null); // true
ComplexSingleton.init(0);
print(complexSingleton == null); // false
print(identical(complexSingleton, ComplexSingleton())); // true
}
Bonjour, qu'en est-il quelque chose comme ça? Très simple implémentation, Injector lui-même est singleton et a également ajouté des classes. Bien sûr, peut être étendu très facilement. Si vous recherchez quelque chose de plus sophistiqué, vérifiez ce paquet: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
void main() {
Injector injector = Injector();
injector.add(() => Person('Filip'));
injector.add(() => City('New York'));
Person person = injector.get<Person>();
City city = injector.get<City>();
print(person.name);
print(city.name);
}
class Person {
String name;
Person(this.name);
}
class City {
String name;
City(this.name);
}
typedef T CreateInstanceFn<T>();
class Injector {
static final Injector _singleton = Injector._internal();
final _factories = Map<String, dynamic>();
factory Injector() {
return _singleton;
}
Injector._internal();
String _generateKey<T>(T type) {
return '${type.toString()}_instance';
}
void add<T>(CreateInstanceFn<T> createInstance) {
final typeKey = _generateKey(T);
_factories[typeKey] = createInstance();
}
T get<T>() {
final typeKey = _generateKey(T);
T instance = _factories[typeKey];
if (instance == null) {
print('Cannot find instance for type $typeKey');
}
return instance;
}
}
Cela devrait marcher.
class GlobalStore {
static GlobalStore _instance;
static GlobalStore get instance {
if(_instance == null)
_instance = new GlobalStore()._();
return _instance;
}
_(){
}
factory GlobalStore()=> instance;
}
Comme je n'aime pas trop utiliser le mot clé new
ou un autre constructeur comme des appels sur des singletons, je préférerais utiliser un getter statique appelé inst
, par exemple:
// the singleton class
class Dao {
// singleton boilerplate
Dao._internal() {}
static final Dao _singleton = new Dao._internal();
static get inst => _singleton;
// business logic
void greet() => print("Hello from singleton");
}
exemple d'utilisation:
Dao.inst.greet(); // call a method
// Dao x = new Dao(); // compiler error: Method not found: 'Dao'
// verify that there only exists one and only one instance
assert(identical(Dao.inst, Dao.inst));
Réponse modifiée de @Seth Ladd pour ceux qui préfèrent le style de singleton Swift tel que .shared
:
class Auth {
// singleton
static final Auth _singleton = Auth._internal();
factory Auth() => _singleton;
Auth._internal();
static Auth get shared => _singleton;
// variables
String username;
String password;
}
Échantillon:
Auth.shared.username = 'abc';