Saya telah melihat beberapa jawaban di bawah ini yang menggambarkan beberapa cara untuk membuat kelas tunggal. Jadi saya berpikir tentang mengapa kita tidak suka objek class_name ini; if (object == null) return object = new class_name; else return object
Meskipun apa gunanya instantiating dua kali? Bukankah seharusnya lebih baik jika ia melemparkan kesalahan saat Anda instantiate untuk yang kedua kalinya?
westoque
53
Saya tidak membuat instance dua kali, hanya mendapatkan referensi ke objek Singleton dua kali. Anda mungkin tidak akan melakukannya dua kali berturut-turut dalam kehidupan nyata :) Saya tidak ingin pengecualian dilemparkan, saya hanya ingin contoh singleton yang sama setiap kali saya mengatakan "Singleton baru ()". Saya akui, ini agak membingungkan ... newtidak berarti "membangun yang baru" di sini, itu hanya mengatakan "jalankan konstruktor".
Seth Ladd
1
Apa sebenarnya yang dilayani oleh kata kunci pabrik di sini? Ini murni menjelaskan implementasi. Mengapa itu diperlukan?
Καrτhικ
4
Agak membingungkan bahwa Anda menggunakan konstruktor untuk mendapatkan contoh. Kata newkunci menunjukkan bahwa kelas adalah instantiated, yang bukan. Saya akan menggunakan metode statis get()atau getInstance()seperti yang saya lakukan di Jawa.
Steven Roose
11
@SethLadd ini sangat bagus tapi saya sarankan perlu beberapa poin penjelasan. Ada sintaks aneh Singleton._internal();yang terlihat seperti pemanggilan metode ketika itu benar-benar definisi konstruktor. Itu _internalnamanya. Dan ada titik desain bahasa yang bagus dimana Dart memungkinkan Anda memulai (dart out?) Menggunakan konstruktor biasa dan kemudian, jika perlu, ubah ke factorymetode tanpa mengubah semua penelepon.
Jerry101
169
Berikut ini adalah perbandingan beberapa cara berbeda untuk membuat singleton di Dart.
SingletonOne one =SingletonOne();SingletonTwo two =SingletonTwo.instance;SingletonThree three =SingletonThree.instance;
catatan:
Saya awalnya mengajukan ini sebagai pertanyaan , tetapi menemukan bahwa semua metode di atas valid dan pilihannya sangat tergantung pada preferensi pribadi.
Saya baru saja mengangkat jawaban Anda. Jauh lebih jelas daripada jawaban yang diterima. Hanya satu pertanyaan lagi: untuk cara kedua dan ketiga, apa gunanya konstruktor pribadi? Saya melihat banyak orang melakukan itu, tetapi saya tidak mengerti intinya. Saya selalu hanya menggunakan static final SingletonThree instance = SingletonThree(). Hal yang sama berlaku untuk cara kedua _instance. Saya tidak tahu apa kerugiannya tidak menggunakan konstruktor pribadi. Sejauh ini, saya tidak menemukan masalah di jalan saya. Cara kedua dan ketiga tidak memblokir panggilan ke konstruktor default.
sgon00
3
@ sgon00, konstruktor pribadi adalah sehingga Anda tidak dapat membuat contoh lain. Kalau tidak ada yang bisa melakukannya SingletonThree instance2 = SingletonThree(). Jika Anda mencoba melakukan ini ketika ada konstruktor pribadi, Anda akan mendapatkan kesalahan:The class 'SingletonThree' doesn't have a default constructor.
Suragch
40
Saya tidak menemukan itu bacaan yang sangat intuitif new Singleton(). Anda harus membaca dokumen untuk mengetahui bahwa newsebenarnya tidak membuat contoh baru, seperti biasanya.
Inilah cara lain untuk melakukan lajang (Pada dasarnya apa yang dikatakan Andrew di atas).
Ini lebih masuk akal bagi saya, terima kasih kepada Greg dan fitur properti tingkat atas panah.
Eason PI
Ini bukan idiom. Ini adalah fitur mimpi untuk memiliki pola singleton membangun dalam bahasa, dan Anda membuangnya karena Anda tidak terbiasa.
Arash
1
Contoh Seth dan contoh ini adalah pola tunggal. Ini benar-benar pertanyaan tentang sintaks "Singleton baru ()" vs "singleton". Saya menemukan yang terakhir lebih jelas. Konstruktor pabrik Dart berguna, tetapi saya tidak berpikir ini adalah kasus penggunaan yang baik untuk mereka. Saya juga berpikir inisialisasi malas malas adalah fitur hebat, yang kurang dimanfaatkan. Baca juga artikel Bob di atas - ia merekomendasikan terhadap lajang dalam banyak kasus.
Variabel tingkat atas itu keren. Namun, siapa pun yang dapat mengimpor single.dart bebas membuat "Impl baru ()". Anda bisa memberikan konstruktor garis bawah ke Impl, tetapi kemudian kode di dalam pustaka tunggal dapat memanggil konstruktor itu.
Seth Ladd
Dan kode dalam implementasi Anda tidak bisa? Bisakah Anda menjelaskan dalam jawaban Anda mengapa lebih baik daripada variabel tingkat atas?
Jan
2
Hai @ Jan, ini tidak lebih baik atau lebih buruk, hanya saja berbeda. Dalam contoh Andrew, Impl bukan kelas tunggal. Dia benar menggunakan variabel level atas untuk membuat instance Singletonmudah diakses. Dalam contoh saya di atas, Singletonkelas adalah singleton nyata, hanya satu contoh yang Singletonbisa ada di isolat.
Seth Ladd
1
Seth, kamu tidak benar. Tidak ada cara di Dart untuk membangun singleton yang benar, karena tidak ada cara untuk membatasi instantiabilitas kelas di dalam perpustakaan yang mendeklarasikan. Itu selalu membutuhkan disiplin dari penulis perpustakaan. Dalam contoh Anda, perpustakaan yang mendeklarasikan dapat memanggil new Singleton._internal()sebanyak yang diinginkan, menciptakan banyak objek dari Singletonkelas. Jika Implkelas dalam contoh Andrew adalah pribadi ( _Impl), itu akan sama dengan contoh Anda. Di sisi lain, singleton adalah antipattern dan tidak ada yang harus menggunakannya.
Ladicek
@Ladicek, jangan Anda percaya pengembang perpustakaan untuk tidak memanggil baru Singelton._internal(). Anda dapat berargumen bahwa pengembang dari kelas singelton dapat membuat instance kelas beberapa kali juga. Tentu ada enum singelton tetapi bagi saya itu hanya penggunaan teori. Enum adalah enum, bukan singelton ... Adapun penggunaan variabel tingkat atas (@Andrew dan @Seth): Tidak bisakah ada yang menulis ke variabel tingkat atas? Itu sama sekali tidak dilindungi, atau apakah saya kehilangan sesuatu?
Tobias Ritzau
12
Berikut cara lain yang mungkin:
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;}
Halo bagaimana dengan yang seperti ini? Implementasi yang sangat sederhana, Injector sendiri adalah singleton dan juga menambahkan kelas ke dalamnya. Tentu saja dapat diperpanjang dengan sangat mudah. Jika Anda mencari sesuatu yang lebih canggih, periksa paket ini: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
Tolong jangan posting pertanyaan tindak lanjut sebagai jawaban. Masalah dengan kode ini adalah sedikit verbose. static GlobalStore get instance => _instance ??= new GlobalStore._();akan lakukan. Apa yang _(){}seharusnya dilakukan? Ini sepertinya berlebihan.
Günter Zöchbauer
maaf, itu saran, bukan pertanyaan tindak lanjut, _ () {} akan membuat konstruktor pribadi bukan?
Vilsad PP
Konstruktor mulai dengan nama kelas. Ini hanya metode instance pribadi normal tanpa tipe pengembalian yang ditentukan.
Günter Zöchbauer
1
Maaf untuk downvote, tapi saya rasa kualitasnya buruk dan tidak menambah nilai selain jawaban yang ada.
Günter Zöchbauer
2
Sementara kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang bagaimana dan / atau mengapa memecahkan masalah akan meningkatkan nilai jangka panjang jawaban.
Karl Richter
0
Karena saya tidak terlalu suka menggunakan newkata kunci atau konstruktor lain seperti panggilan pada lajang, saya lebih suka menggunakan pengambil statis yang dipanggil instmisalnya:
// the singleton classclassDao{// singleton boilerplateDao._internal(){}staticfinalDao _singleton =newDao._internal();staticget inst => _singleton;// business logicvoid greet()=> print("Hello from singleton");}
contoh penggunaan:
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));
Jawaban:
Berkat konstruktor pabrik Dart , mudah membangun singleton:
Anda dapat membangunnya seperti ini
sumber
new
tidak berarti "membangun yang baru" di sini, itu hanya mengatakan "jalankan konstruktor".new
kunci menunjukkan bahwa kelas adalah instantiated, yang bukan. Saya akan menggunakan metode statisget()
ataugetInstance()
seperti yang saya lakukan di Jawa.Singleton._internal();
yang terlihat seperti pemanggilan metode ketika itu benar-benar definisi konstruktor. Itu_internal
namanya. Dan ada titik desain bahasa yang bagus dimana Dart memungkinkan Anda memulai (dart out?) Menggunakan konstruktor biasa dan kemudian, jika perlu, ubah kefactory
metode tanpa mengubah semua penelepon.Berikut ini adalah perbandingan beberapa cara berbeda untuk membuat singleton di Dart.
1. Konstruktor pabrik
2. Bidang statis dengan pengambil
3. Bidang statis
Bagaimana cara instan
Para lajang di atas dipakai seperti ini:
catatan:
Saya awalnya mengajukan ini sebagai pertanyaan , tetapi menemukan bahwa semua metode di atas valid dan pilihannya sangat tergantung pada preferensi pribadi.
sumber
static final SingletonThree instance = SingletonThree()
. Hal yang sama berlaku untuk cara kedua_instance
. Saya tidak tahu apa kerugiannya tidak menggunakan konstruktor pribadi. Sejauh ini, saya tidak menemukan masalah di jalan saya. Cara kedua dan ketiga tidak memblokir panggilan ke konstruktor default.SingletonThree instance2 = SingletonThree()
. Jika Anda mencoba melakukan ini ketika ada konstruktor pribadi, Anda akan mendapatkan kesalahan:The class 'SingletonThree' doesn't have a default constructor.
Saya tidak menemukan itu bacaan yang sangat intuitif
new Singleton()
. Anda harus membaca dokumen untuk mengetahui bahwanew
sebenarnya tidak membuat contoh baru, seperti biasanya.Inilah cara lain untuk melakukan lajang (Pada dasarnya apa yang dikatakan Andrew di atas).
lib / thing.dart
main.dart
Perhatikan bahwa singleton tidak dapat dibuat sampai pertama kali pengambil tersebut dipanggil karena inisialisasi malas dari Dart.
Jika Anda mau, Anda juga dapat menerapkan lajang sebagai pengambil statis di kelas lajang. yaitu
Thing.singleton
, bukannya pengambil tingkat atas.Baca juga pendapat Bob Nystrom tentang para lajang dari buku pola pemrograman Game-nya .
sumber
Bagaimana dengan hanya menggunakan variabel global dalam perpustakaan Anda, seperti itu?
single.dart
:main.dart
:Atau ini disukai?
Pola tunggal diperlukan di Jawa di mana konsep global tidak ada, tetapi sepertinya Anda tidak perlu pergi jauh-jauh di Dart.
sumber
Singleton
mudah diakses. Dalam contoh saya di atas,Singleton
kelas adalah singleton nyata, hanya satu contoh yangSingleton
bisa ada di isolat.new Singleton._internal()
sebanyak yang diinginkan, menciptakan banyak objek dariSingleton
kelas. JikaImpl
kelas dalam contoh Andrew adalah pribadi (_Impl
), itu akan sama dengan contoh Anda. Di sisi lain, singleton adalah antipattern dan tidak ada yang harus menggunakannya.Singelton._internal()
. Anda dapat berargumen bahwa pengembang dari kelas singelton dapat membuat instance kelas beberapa kali juga. Tentu ada enum singelton tetapi bagi saya itu hanya penggunaan teori. Enum adalah enum, bukan singelton ... Adapun penggunaan variabel tingkat atas (@Andrew dan @Seth): Tidak bisakah ada yang menulis ke variabel tingkat atas? Itu sama sekali tidak dilindungi, atau apakah saya kehilangan sesuatu?Berikut cara lain yang mungkin:
sumber
Dart singleton oleh konstruktor & pabrik
sumber
Singleton yang tidak dapat mengubah objek setelah contoh
sumber
Diubah @Seth Ladd untuk siapa yang lebih suka gaya Swift singleton seperti
.shared
:Sampel:
sumber
Setelah membaca semua alternatif saya menemukan ini, yang mengingatkan saya pada "singleton klasik":
sumber
getInstance
metode diinstance
properti seperti ini:static AccountService get instance => _instance;
Ini jawaban sederhana:
sumber
Berikut adalah contoh singkat yang menggabungkan solusi lain. Mengakses singleton dapat dilakukan dengan:
singleton
variabel global yang menunjuk ke instance.Singleton.instance
Pola umum .Catatan: Anda harus menerapkan hanya satu dari tiga opsi sehingga kode menggunakan singleton konsisten.
Jika Anda perlu melakukan inisialisasi yang kompleks, Anda hanya perlu melakukannya sebelum menggunakan instance nanti dalam program.
Contoh
sumber
Halo bagaimana dengan yang seperti ini? Implementasi yang sangat sederhana, Injector sendiri adalah singleton dan juga menambahkan kelas ke dalamnya. Tentu saja dapat diperpanjang dengan sangat mudah. Jika Anda mencari sesuatu yang lebih canggih, periksa paket ini: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
sumber
Ini seharusnya bekerja.
sumber
static GlobalStore get instance => _instance ??= new GlobalStore._();
akan lakukan. Apa yang_(){}
seharusnya dilakukan? Ini sepertinya berlebihan.Karena saya tidak terlalu suka menggunakan
new
kata kunci atau konstruktor lain seperti panggilan pada lajang, saya lebih suka menggunakan pengambil statis yang dipanggilinst
misalnya:contoh penggunaan:
sumber