Vi várias respostas abaixo, que descrevem várias maneiras de criar uma classe única. Então, estou pensando por que não gostamos desse objeto class_name; if (object == null) retorna object = new class_name; outro objeto de retorno
Embora qual o sentido de instanciar duas vezes? Não deveria ser melhor se ocorresse um erro ao instancia-lo pela segunda vez?
westoque
53
Não estou instanciando duas vezes, apenas obtendo uma referência a um objeto Singleton duas vezes. Você provavelmente não faria isso duas vezes seguidas na vida real :) Eu não gostaria que uma exceção fosse lançada, só quero a mesma instância singleton toda vez que digo "new Singleton ()". Eu admito, é um pouco confuso ... newnão significa "construir um novo" aqui, apenas diz "executar o construtor".
Seth Ladd
1
O que exatamente a palavra-chave de fábrica serve aqui? É apenas uma anotação da implementação. Por que é necessário?
Καrτhικ
4
É meio confuso que você esteja usando um construtor para obter a instância. A newpalavra-chave sugere que a classe é instanciada, o que não é. Eu iria para um método estático get()ou getInstance()como eu faço em Java.
Steven Roose
11
@SethLadd isso é muito bom, mas sugiro que ele precise de alguns pontos de explicação. Existe a sintaxe estranha Singleton._internal();que se parece com uma chamada de método quando é realmente uma definição de construtor. Aqui está o _internalnome. E há o ponto de design da linguagem bacana que o Dart permite que você inicie (dart out?) Usando um construtor comum e, se necessário, altere-o para um factorymétodo sem alterar todos os chamadores.
precisa saber é o seguinte
169
Aqui está uma comparação de várias maneiras diferentes de criar um singleton no Dart.
SingletonOne one =SingletonOne();SingletonTwo two =SingletonTwo.instance;SingletonThree three =SingletonThree.instance;
Nota:
Eu originalmente fiz isso como uma pergunta , mas descobri que todos os métodos acima são válidos e a escolha depende em grande parte da preferência pessoal.
Acabei de votar em sua resposta. Muito mais claro que a resposta aceita. Apenas mais uma pergunta: para a segunda e terceira via, qual é o sentido do construtor privado? Vi muitas pessoas fazendo isso, mas não entendo o ponto. Eu sempre simplesmente uso static final SingletonThree instance = SingletonThree(). O mesmo vale para o segundo caminho para _instance. Não sei qual é a desvantagem de não usar um construtor privado. Até agora, não encontro nenhum problema no meu caminho. A segunda e a terceira maneira não estão bloqueando a chamada para o construtor padrão de qualquer maneira.
sgon00
3
@ sgon00, o construtor privado é para que você não possa criar outra instância. Caso contrário, alguém poderia fazer SingletonThree instance2 = SingletonThree(). Se você tentar fazer isso quando houver um construtor privado, receberá o erro:The class 'SingletonThree' doesn't have a default constructor.
Suragch
40
Não acho uma leitura muito intuitiva new Singleton(). Você precisa ler os documentos para saber quenew na verdade, não está criando uma nova instância, como faria normalmente.
Aqui está outra maneira de fazer singletons (basicamente o que Andrew disse acima).
Observe que o singleton não é criado até a primeira vez que o getter é chamado devido à inicialização lenta do Dart.
Se preferir, também é possível implementar singletons como getter estático na classe singleton. ieThing.singleton , em vez de um getter de nível superior.
Isso faz mais sentido para mim, graças a Greg e ao recurso de propriedade de nível superior do dardo.
Eason PI
Isso não é idiomático. É um recurso de sonho ter um padrão de singleton construído no idioma, e você o está descartando porque não está acostumado.
Arash
1
O exemplo de Seth e este exemplo são padrões únicos. É realmente uma questão de sintaxe "novo Singleton ()" vs "singleton". Acho o último mais claro. Os construtores de fábrica da Dart são úteis, mas não acho que esse seja um bom caso de uso para eles. Eu também acho que a inicialização preguiçosa de Dart é um ótimo recurso, que é subutilizado. Leia também o artigo de Bob acima - ele recomenda contra singletons na maioria dos casos.
import'single.dart';void main(){var a =Singleton;var b =Singleton;
a.i =2;
print(b.i);}
Ou isso é desaprovado?
O padrão singleton é necessário em Java, onde o conceito de globais não existe, mas parece que você não precisa percorrer o caminho mais longo no Dart.
Variáveis de nível superior são legais. No entanto, qualquer pessoa que possa importar single.dart pode criar um "novo Impl ()". Você poderia dar um construtor de sublinhado ao Impl, mas o código dentro da biblioteca singleton poderia chamar esse construtor.
Seth Ladd
E o código na sua implementação não pode? Você pode explicar em sua resposta por que é melhor do que uma variável de nível superior?
Janeiro
2
Oi @Jan, não é melhor ou pior, é apenas diferente. No exemplo de Andrew, o Impl não é uma classe singleton. Ele usou corretamente uma variável de nível superior para facilitar o Singletonacesso à instância . No meu exemplo acima, a Singletonclasse é um singleton real, apenas uma instância de Singletonpode existir no isolado.
Seth Ladd
1
Seth, você não está certo. Não há como o Dart criar um verdadeiro singleton, pois não há como restringir a instabilidade de uma classe dentro da biblioteca declaradora. Sempre requer disciplina do autor da biblioteca. No seu exemplo, a biblioteca declaradora pode chamar new Singleton._internal()quantas vezes quiser, criando muitos objetos da Singletonclasse. Se a Implclasse no exemplo de Andrew fosse private ( _Impl), seria a mesma que o seu exemplo. Por outro lado, o singleton é um antipadrão e ninguém deve usá-lo de qualquer maneira.
Ladicek
@Ladicek, não confie nos desenvolvedores de uma biblioteca para não chamar de novo Singelton._internal(). Você pode argumentar que os desenvolvedores da classe singelton também poderiam instatá-la várias vezes. Claro que existe o enum singelton, mas para mim é apenas de uso teórico. Um enum é um enum, não um singelton ... Quanto ao uso de variáveis de nível superior (@Andrew e @Seth): ninguém poderia escrever na variável de nível superior? É de nenhuma maneira protegida, ou estou faltando alguma coisa?
Tobias Ritzau 9/10/12
12
Aqui está outra maneira possível:
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;}
Olá, que tal algo assim? Implementação muito simples, o próprio Injector é único e também adicionou classes a ele. Claro que pode ser estendido com muita facilidade. Se você está procurando algo mais sofisticado, verifique este pacote: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
Não poste perguntas de acompanhamento como respostas. O problema com esse código é que ele é um pouco detalhado. static GlobalStore get instance => _instance ??= new GlobalStore._();faria. O que _(){}deveria fazer? Isso parece redundante.
Günter Zöchbauer 13/10
desculpe, isso foi uma sugestão, não uma pergunta de acompanhamento, _ () {} criará um construtor privado, certo?
Vilsad PP
Os construtores começam com o nome da classe. Este é apenas um método de instância privada normal sem um tipo de retorno especificado.
Günter Zöchbauer 13/10
1
Desculpe pelo voto negativo, mas acho que é de baixa qualidade e não agrega nenhum valor além das respostas existentes.
Günter Zöchbauer 13/10
2
Embora esse código possa responder à pergunta, fornecer um contexto adicional sobre como e / ou por que resolve o problema melhoraria o valor a longo prazo da resposta.
Karl Richter
0
Como não gosto muito de usar a newpalavra - chave ou outro construtor como chamadas em singletons, eu preferiria usar um getter estático chamado, instpor exemplo:
// the singleton classclassDao{// singleton boilerplateDao._internal(){}staticfinalDao _singleton =newDao._internal();staticget inst => _singleton;// business logicvoid greet()=> print("Hello from singleton");}
exemplo 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));
Respostas:
Graças aos construtores de fábrica da Dart , é fácil criar um singleton:
Você pode construir assim
fonte
new
não significa "construir um novo" aqui, apenas diz "executar o construtor".new
palavra-chave sugere que a classe é instanciada, o que não é. Eu iria para um método estáticoget()
ougetInstance()
como eu faço em Java.Singleton._internal();
que se parece com uma chamada de método quando é realmente uma definição de construtor. Aqui está o_internal
nome. E há o ponto de design da linguagem bacana que o Dart permite que você inicie (dart out?) Usando um construtor comum e, se necessário, altere-o para umfactory
método sem alterar todos os chamadores.Aqui está uma comparação de várias maneiras diferentes de criar um singleton no Dart.
1. Construtor de fábrica
2. Campo estático com getter
3. campo estático
Como instanstiate
Os singletons acima são instanciados assim:
Nota:
Eu originalmente fiz isso como uma pergunta , mas descobri que todos os métodos acima são válidos e a escolha depende em grande parte da preferência pessoal.
fonte
static final SingletonThree instance = SingletonThree()
. O mesmo vale para o segundo caminho para_instance
. Não sei qual é a desvantagem de não usar um construtor privado. Até agora, não encontro nenhum problema no meu caminho. A segunda e a terceira maneira não estão bloqueando a chamada para o construtor padrão de qualquer maneira.SingletonThree instance2 = SingletonThree()
. Se você tentar fazer isso quando houver um construtor privado, receberá o erro:The class 'SingletonThree' doesn't have a default constructor.
Não acho uma leitura muito intuitiva
new Singleton()
. Você precisa ler os documentos para saber quenew
na verdade, não está criando uma nova instância, como faria normalmente.Aqui está outra maneira de fazer singletons (basicamente o que Andrew disse acima).
lib / thing.dart
main.dart
Observe que o singleton não é criado até a primeira vez que o getter é chamado devido à inicialização lenta do Dart.
Se preferir, também é possível implementar singletons como getter estático na classe singleton. ie
Thing.singleton
, em vez de um getter de nível superior.Leia também a opinião de Bob Nystrom sobre singletons de seu livro de padrões de programação de jogos .
fonte
Que tal usar apenas uma variável global em sua biblioteca?
single.dart
:main.dart
:Ou isso é desaprovado?
O padrão singleton é necessário em Java, onde o conceito de globais não existe, mas parece que você não precisa percorrer o caminho mais longo no Dart.
fonte
Singleton
acesso à instância . No meu exemplo acima, aSingleton
classe é um singleton real, apenas uma instância deSingleton
pode existir no isolado.new Singleton._internal()
quantas vezes quiser, criando muitos objetos daSingleton
classe. Se aImpl
classe no exemplo de Andrew fosse private (_Impl
), seria a mesma que o seu exemplo. Por outro lado, o singleton é um antipadrão e ninguém deve usá-lo de qualquer maneira.Singelton._internal()
. Você pode argumentar que os desenvolvedores da classe singelton também poderiam instatá-la várias vezes. Claro que existe o enum singelton, mas para mim é apenas de uso teórico. Um enum é um enum, não um singelton ... Quanto ao uso de variáveis de nível superior (@Andrew e @Seth): ninguém poderia escrever na variável de nível superior? É de nenhuma maneira protegida, ou estou faltando alguma coisa?Aqui está outra maneira possível:
fonte
Dart singleton por const constructor & factory
fonte
Singleton que não pode alterar o objeto após a instância
fonte
Resposta modificada de @Seth Ladd para quem prefere o estilo Swift de singleton como
.shared
:Amostra:
fonte
Depois de ler todas as alternativas, eu vim com isso, o que me lembra um "singleton clássico":
fonte
getInstance
método em umainstance
propriedade como esta:static AccountService get instance => _instance;
Aqui está uma resposta simples:
fonte
Aqui está um exemplo conciso que combina as outras soluções. O acesso ao singleton pode ser feito por:
singleton
variável global que aponta para a instância.Singleton.instance
padrão .Nota: Você deve implementar apenas uma das três opções para que o código usando o singleton seja consistente.
Se você precisar fazer uma inicialização complexa, precisará fazê-lo antes de usar a instância posteriormente no programa.
Exemplo
fonte
Olá, que tal algo assim? Implementação muito simples, o próprio Injector é único e também adicionou classes a ele. Claro que pode ser estendido com muita facilidade. Se você está procurando algo mais sofisticado, verifique este pacote: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
fonte
Isso deve funcionar.
fonte
static GlobalStore get instance => _instance ??= new GlobalStore._();
faria. O que_(){}
deveria fazer? Isso parece redundante.Como não gosto muito de usar a
new
palavra - chave ou outro construtor como chamadas em singletons, eu preferiria usar um getter estático chamado,inst
por exemplo:exemplo de uso:
fonte