web-dev-qa-db-fra.com

Comment construisez-vous un Singleton dans Dart?

Le modèle singleton garantit qu'une seule instance d'une classe est créée. Comment puis-je construire cela dans Dart?

78
Seth Ladd

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
}
122
Seth Ladd

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 .

21
Greg Lowe

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.

12
Andrew Gerrand

Voici une comparaison de plusieurs façons différentes de créer un singleton dans Dart.

1. constructeur d'usine

class SingletonOne {

  SingletonOne._privateConstructor();

  static final SingletonOne _instance = SingletonOne._privateConstructor();

  factory SingletonOne(){
    return _instance;
  }

}

2. Champ statique avec getter

class SingletonTwo {

  SingletonTwo._privateConstructor();

  static final SingletonTwo _instance = SingletonTwo._privateConstructor();

  static SingletonTwo get instance { return _instance;}

}

3. Champ statique

class SingletonThree {

  SingletonThree._privateConstructor();

  static final SingletonThree instance = SingletonThree._privateConstructor();

}

Comment instancier

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.

12
Suragch

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;
}
8
iBob101

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()));
}
8
Ticore Shih

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}
1
Lucas Breitembach

Voici un exemple concis qui combine les autres solutions. L'accès au singleton peut être fait par:

  • Utilisation d'une variable globale singleton qui pointe vers l'instance.
  • Le modèle Singleton.instance commun.
  • Utilisation du constructeur par défaut, qui est une fabrique qui renvoie l'instance.

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
}
1
Jacob Phillips

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;
  }
}
0
Filip Jerga

Cela devrait marcher.

class GlobalStore {
    static GlobalStore _instance;
    static GlobalStore get instance {
       if(_instance == null)
           _instance = new GlobalStore()._();
       return _instance;
    }

    _(){

    }
    factory GlobalStore()=> instance;


}
0
Vilsad P P

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));
0
sprestel

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';
0
DazChong