He visto varias respuestas a continuación que describen varias formas de hacer un singleton de clase. Así que estoy pensando por qué no nos gusta este objeto class_name; if (object == null) return object = new class_name; más devolver objeto
Aunque, ¿cuál es el punto de instanciarlo dos veces? ¿No debería ser mejor si arrojó un error cuando lo instancia por segunda vez?
Westoque
53
No lo instanciaré dos veces, solo obtendré una referencia a un objeto Singleton dos veces. Probablemente no lo harías dos veces seguidas en la vida real :) No quisiera que se lanzara una excepción, solo quiero la misma instancia de singleton cada vez que digo "new Singleton ()". Lo admito, es un poco confuso ... newno significa "construir uno nuevo" aquí, solo dice "ejecutar el constructor".
Seth Ladd
1
¿Qué sirve exactamente la palabra clave de fábrica aquí? Es puramente anotar la implementación. ¿Por qué se requiere?
Καrτhικ
44
Es un poco confuso que esté utilizando un constructor para obtener la instancia. La newpalabra clave sugiere que la clase se instancia, lo que no es. Iría por un método estático get()o getInstance()como lo hago en Java.
Steven Roose
11
@SethLadd esto es muy bueno, pero sugiero que necesita un par de puntos de explicación. Existe la sintaxis extraña Singleton._internal();que parece una llamada a un método cuando realmente es una definición de constructor. Ahí está el _internalnombre. Y existe el ingenioso punto de diseño del lenguaje que Dart le permite comenzar (¿lanzarse?) Usando un constructor ordinario y luego, si es necesario, cambiarlo a un factorymétodo sin cambiar todas las llamadas.
Jerry101
169
Aquí hay una comparación de varias formas diferentes de crear un singleton en Dart.
Los singletons anteriores se instancian de esta manera:
SingletonOne one =SingletonOne();SingletonTwo two =SingletonTwo.instance;SingletonThree three =SingletonThree.instance;
Nota:
Originalmente hice esto como una pregunta , pero descubrí que todos los métodos anteriores son válidos y la elección depende en gran medida de la preferencia personal.
Acabo de votar tu respuesta. Mucho más claro que la respuesta aceptada. Solo una pregunta más: para la segunda y tercera forma, ¿cuál es el punto del constructor privado? Vi que mucha gente hizo eso, pero no entiendo el punto. Siempre lo uso simplemente static final SingletonThree instance = SingletonThree(). Lo mismo ocurre con la segunda forma para _instance. No sé cuál es la desventaja de no usar un constructor privado. Hasta ahora, no encuentro ningún problema en mi camino. La segunda y tercera forma no están bloqueando la llamada al constructor predeterminado de todos modos.
sgon00
3
@ sgon00, el constructor privado es para que no puedas hacer otra instancia. De lo contrario, cualquiera podría hacerlo SingletonThree instance2 = SingletonThree(). Si intenta hacer esto cuando hay un constructor privado, obtendrá el error:The class 'SingletonThree' doesn't have a default constructor.
Suragch
40
No me parece una lectura muy intuitiva new Singleton(). Debe leer los documentos para saber que en newrealidad no está creando una nueva instancia, como lo haría normalmente.
Aquí hay otra forma de hacer singletons (Básicamente lo que Andrew dijo anteriormente).
Tenga en cuenta que el singleton no se crea hasta la primera vez que se llama al getter debido a la inicialización diferida de Dart.
Si lo prefiere, también puede implementar singletons como getter estático en la clase singleton. es decir Thing.singleton, en lugar de un captador de nivel superior.
Esto tiene más sentido para mí, gracias a Greg y la característica de propiedad de nivel superior de dardo.
Eason PI
Esto no es idiomático. Es una característica ideal tener una construcción de patrón único en el lenguaje, y lo está descartando porque no está acostumbrado.
Arash
1
Tanto el ejemplo de Seth como este ejemplo son patrones únicos. Es realmente una cuestión de sintaxis "new Singleton ()" vs "singleton". Este último me parece más claro. Los constructores de fábrica de Dart son útiles, pero no creo que sea un buen caso de uso para ellos. También creo que la inicialización perezosa de Dart es una gran característica, que está infrautilizada. Lea también el artículo anterior de Bob: él recomienda no usar singleton en la mayoría de los casos.
Las variables de nivel superior son geniales. Sin embargo, cualquiera que pueda importar single.dart es libre de construir un "nuevo Impl ()". Podría darle un constructor de subrayado a Impl, pero luego el código dentro de la biblioteca singleton podría llamar a ese constructor.
Seth Ladd
¿Y el código en su implementación no puede? ¿Puede explicar en su respuesta por qué es mejor que una variable de nivel superior?
Jan
2
Hola @ Jan, no es mejor ni peor, es simplemente diferente. En el ejemplo de Andrew, Impl no es una clase singleton. Utilizó correctamente una variable de nivel superior para facilitar el Singletonacceso a la instancia . En mi ejemplo anterior, la Singletonclase es un singleton real, solo una instancia de Singletonpuede existir en el aislamiento.
Seth Ladd
1
Seth, no tienes razón. No hay forma en Dart de construir un verdadero singleton, ya que no hay forma de restringir la instanciación de una clase dentro de la biblioteca de declaración. Siempre requiere disciplina del autor de la biblioteca. En su ejemplo, la biblioteca declarante puede llamar new Singleton._internal()tantas veces como quiera, creando muchos objetos de la Singletonclase. Si la Implclase en el ejemplo de Andrew fuera privada ( _Impl), sería la misma que su ejemplo. Por otro lado, singleton es un antipatrón y nadie debería usarlo de todos modos.
Ladicek
@Ladicek, no confíes en que los desarrolladores de una biblioteca no llamen nuevo Singelton._internal(). Puede argumentar que los desarrolladores de la clase singelton también podrían instaurar la clase varias veces. Claro que existe el enum singelton, pero para mí es solo de uso teórico. Una enumeración es una enumeración, no un singelton ... En cuanto al uso de variables de nivel superior (@Andrew y @Seth): ¿Nadie podría escribir en la variable de nivel superior? De ninguna manera está protegido, ¿o me estoy perdiendo algo?
Tobias Ritzau
12
Aquí hay otra forma posible:
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}classSingleton{staticfinalSingleton _singleton =newSingleton._internal();Singleton._internal();staticSingletonget instance => _singleton;var somedata;}
Hola, ¿qué tal algo como esto? Implementación muy simple, el inyector en sí mismo es singleton y también agregó clases en él. Por supuesto, se puede extender muy fácilmente. Si está buscando algo más sofisticado, consulte este paquete: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
No publique preguntas de seguimiento como respuestas. El problema con este código es que es un poco detallado. static GlobalStore get instance => _instance ??= new GlobalStore._();haría. ¿Qué se _(){}supone que debe hacer? Esto parece redundante.
Günter Zöchbauer
lo siento, fue una sugerencia, no una pregunta de seguimiento, _ () {} creará un constructor privado, ¿verdad?
Vilsad PP
Los constructores comienzan con el nombre de la clase. Este es solo un método de instancia privada normal sin un tipo de retorno especificado.
Günter Zöchbauer
1
Perdón por el voto negativo, pero creo que es de baja calidad y no agrega ningún valor además de las respuestas existentes.
Günter Zöchbauer
2
Si bien este código puede responder la pregunta, proporcionar un contexto adicional con respecto a cómo y / o por qué resuelve el problema mejoraría el valor a largo plazo de la respuesta.
Karl Richter
0
Como no soy muy aficionado a usar la newpalabra clave u otro constructor como llamadas en singletons, preferiría usar un getter estático llamado, instpor ejemplo:
// the singleton classclassDao{// singleton boilerplateDao._internal(){}staticfinalDao _singleton =newDao._internal();staticget inst => _singleton;// business logicvoid greet()=> print("Hello from singleton");}
ejemplo de uso:
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 instanceassert(identical(Dao.inst,Dao.inst));
Respuestas:
Gracias a los constructores de fábrica de Dart , es fácil construir un singleton:
Puedes construirlo así
fuente
new
no significa "construir uno nuevo" aquí, solo dice "ejecutar el constructor".new
palabra clave sugiere que la clase se instancia, lo que no es. Iría por un método estáticoget()
ogetInstance()
como lo hago en Java.Singleton._internal();
que parece una llamada a un método cuando realmente es una definición de constructor. Ahí está el_internal
nombre. Y existe el ingenioso punto de diseño del lenguaje que Dart le permite comenzar (¿lanzarse?) Usando un constructor ordinario y luego, si es necesario, cambiarlo a unfactory
método sin cambiar todas las llamadas.Aquí hay una comparación de varias formas diferentes de crear un singleton en Dart.
1. Constructor de fábrica
2. Campo estático con captador
3. campo estático
Cómo instaurar
Los singletons anteriores se instancian de esta manera:
Nota:
Originalmente hice esto como una pregunta , pero descubrí que todos los métodos anteriores son válidos y la elección depende en gran medida de la preferencia personal.
fuente
static final SingletonThree instance = SingletonThree()
. Lo mismo ocurre con la segunda forma para_instance
. No sé cuál es la desventaja de no usar un constructor privado. Hasta ahora, no encuentro ningún problema en mi camino. La segunda y tercera forma no están bloqueando la llamada al constructor predeterminado de todos modos.SingletonThree instance2 = SingletonThree()
. Si intenta hacer esto cuando hay un constructor privado, obtendrá el error:The class 'SingletonThree' doesn't have a default constructor.
No me parece una lectura muy intuitiva
new Singleton()
. Debe leer los documentos para saber que ennew
realidad no está creando una nueva instancia, como lo haría normalmente.Aquí hay otra forma de hacer singletons (Básicamente lo que Andrew dijo anteriormente).
lib / thing.dart
main.dart
Tenga en cuenta que el singleton no se crea hasta la primera vez que se llama al getter debido a la inicialización diferida de Dart.
Si lo prefiere, también puede implementar singletons como getter estático en la clase singleton. es decir
Thing.singleton
, en lugar de un captador de nivel superior.Lea también la versión de Bob Nystrom sobre los singletons de su libro de patrones de programación de juegos .
fuente
¿Qué tal si usas una variable global dentro de tu biblioteca, así?
single.dart
:main.dart
:¿O está mal visto?
El patrón singleton es necesario en Java, donde el concepto de globals no existe, pero parece que no deberías tener que recorrer el camino en Dart.
fuente
Singleton
acceso a la instancia . En mi ejemplo anterior, laSingleton
clase es un singleton real, solo una instancia deSingleton
puede existir en el aislamiento.new Singleton._internal()
tantas veces como quiera, creando muchos objetos de laSingleton
clase. Si laImpl
clase en el ejemplo de Andrew fuera privada (_Impl
), sería la misma que su ejemplo. Por otro lado, singleton es un antipatrón y nadie debería usarlo de todos modos.Singelton._internal()
. Puede argumentar que los desarrolladores de la clase singelton también podrían instaurar la clase varias veces. Claro que existe el enum singelton, pero para mí es solo de uso teórico. Una enumeración es una enumeración, no un singelton ... En cuanto al uso de variables de nivel superior (@Andrew y @Seth): ¿Nadie podría escribir en la variable de nivel superior? De ninguna manera está protegido, ¿o me estoy perdiendo algo?Aquí hay otra forma posible:
fuente
Dart Singleton de Const Constructor & Factory
fuente
Singleton que no puede cambiar el objeto después de la instancia
fuente
Respuesta de @Seth Ladd modificada para quién prefiere el estilo Swift de singleton como
.shared
:Muestra:
fuente
Después de leer todas las alternativas se me ocurrió esto, que me recuerda un "singleton clásico":
fuente
getInstance
método en unainstance
propiedad como esta:static AccountService get instance => _instance;
Aquí hay una respuesta simple:
fuente
Aquí hay un ejemplo conciso que combina las otras soluciones. El acceso al singleton se puede hacer mediante:
singleton
variable global que apunta a la instancia.Singleton.instance
patrón común .Nota: Debe implementar solo una de las tres opciones para que el código que use el singleton sea coherente.
Si necesita hacer una inicialización compleja, solo tendrá que hacerlo antes de usar la instancia más adelante en el programa.
Ejemplo
fuente
Hola, ¿qué tal algo como esto? Implementación muy simple, el inyector en sí mismo es singleton y también agregó clases en él. Por supuesto, se puede extender muy fácilmente. Si está buscando algo más sofisticado, consulte este paquete: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
fuente
Esto debería funcionar.
fuente
static GlobalStore get instance => _instance ??= new GlobalStore._();
haría. ¿Qué se_(){}
supone que debe hacer? Esto parece redundante.Como no soy muy aficionado a usar la
new
palabra clave u otro constructor como llamadas en singletons, preferiría usar un getter estático llamado,inst
por ejemplo:ejemplo de uso:
fuente