सिंगलटन पैटर्न यह सुनिश्चित करता है कि किसी वर्ग का केवल एक उदाहरण कभी बनाया जाए। मैं इसे डार्ट में कैसे बनाऊं?
सिंगलटन पैटर्न यह सुनिश्चित करता है कि किसी वर्ग का केवल एक उदाहरण कभी बनाया जाए। मैं इसे डार्ट में कैसे बनाऊं?
जवाबों:
डार्ट के कारखाने के निर्माणकर्ताओं के लिए धन्यवाद , एक सिंगलटन का निर्माण करना आसान है:
class Singleton {
static final Singleton _singleton = Singleton._internal();
factory Singleton() {
return _singleton;
}
Singleton._internal();
}
आप इसका निर्माण इस तरह से कर सकते हैं
main() {
var s1 = Singleton();
var s2 = Singleton();
print(identical(s1, s2)); // true
print(s1 == s2); // true
}
new
इसका मतलब यह नहीं है कि "एक नया निर्माण" यहां, यह सिर्फ "कंस्ट्रक्टर को चलाने" का कहना है।
new
कीवर्ड पता चलता है कि वर्ग instantiated है, जो ऐसा नहीं है। मैं एक स्थिर विधि के लिए जाऊँगा get()
या getInstance()
जैसे मैं जावा में करता हूँ।
Singleton._internal();
जो वास्तव में एक रचनाकार की परिभाषा के अनुसार एक विधि कॉल की तरह दिखता है। नहीं है _internal
नाम। और निफ्टी भाषा का डिज़ाइन बिंदु है जिसे डार्ट आपको एक साधारण कंस्ट्रक्टर का उपयोग करके शुरू करने (डार्ट आउट) की अनुमति देता है और फिर, यदि आवश्यक हो, तो factory
सभी कॉलर्स को बदले बिना इसे एक विधि में बदल दें।
यहाँ डार्ट में एक सिंगलटन बनाने के लिए कई अलग-अलग तरीकों की तुलना है।
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 => _instance;
}
class SingletonThree {
SingletonThree._privateConstructor();
static final SingletonThree instance = SingletonThree._privateConstructor();
}
उपर्युक्त सिंग्नलों को इस तरह त्वरित किया जाता है:
SingletonOne one = SingletonOne();
SingletonTwo two = SingletonTwo.instance;
SingletonThree three = SingletonThree.instance;
ध्यान दें:
मैंने मूल रूप से इसे एक प्रश्न के रूप में पूछा था , लेकिन यह पता चला कि उपरोक्त सभी विधियां वैध हैं और चुनाव काफी हद तक व्यक्तिगत पसंद पर निर्भर करता है।
static final SingletonThree instance = SingletonThree()
। उसी के लिए दूसरा रास्ता जाता है _instance
। मुझे नहीं पता कि निजी कंस्ट्रक्टर का उपयोग न करने का क्या नुकसान है। अब तक, मुझे अपने रास्ते में कोई समस्या नहीं है। दूसरे और तीसरे तरीके कॉल को डिफॉल्ट कंस्ट्रक्टर के लिए वैसे भी ब्लॉक नहीं कर रहे हैं।
SingletonThree instance2 = SingletonThree()
। यदि आप निजी कंस्ट्रक्टर होने पर ऐसा करने का प्रयास करते हैं, तो आपको यह त्रुटि The class 'SingletonThree' doesn't have a default constructor.
मुझे यह पढ़ने में बहुत सहज नहीं लगता new Singleton()
। आपको यह जानने के लिए डॉक्स पढ़ना होगा कि new
यह वास्तव में एक नया उदाहरण नहीं बना रहा है, जैसा कि सामान्य रूप से होता है।
यहां एक और तरीका है सिंगलेट्स (मूल रूप से एंड्रयू ने ऊपर जो कहा है)।
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();
}
ध्यान दें कि डार्ट के आलसी इनिशियलाइजेशन के कारण पहली बार गेट्टर कहे जाने तक सिंगलटन नहीं बनता है।
यदि आप चाहें तो आप सिंगलटन को सिंगलटन क्लास पर स्थिर गेट्टर के रूप में भी लागू कर सकते हैं। यानी Thing.singleton
, एक टॉप लेवल गेटटर की जगह।
इसके अलावा बॉब निस्ट्रोम की टेक को उनके गेम प्रोग्रामिंग पैटर्न बुक से एकल पर पढ़ें ।
अपने पुस्तकालय के भीतर एक वैश्विक चर का उपयोग करने के बारे में क्या, जैसे?
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);
}
या इस पर भरोसा है?
जावा में सिंगलटन पैटर्न आवश्यक है, जहां ग्लोबल्स की अवधारणा मौजूद नहीं है, लेकिन ऐसा लगता है कि आपको डार्ट के आसपास लंबा रास्ता तय करने की आवश्यकता नहीं है।
Singleton
को एक्सेस करने में आसान बनाने के लिए उन्होंने शीर्ष-स्तरीय चर का सही उपयोग किया । ऊपर मेरे उदाहरण में, Singleton
क्लास एक वास्तविक सिंगलटन है, Singleton
आइसोलेट में कभी भी केवल एक ही उदाहरण मौजूद हो सकता है।
new Singleton._internal()
जितनी बार चाहे उतनी बार कॉल कर सकता है, जिससे Singleton
कक्षा की बहुत सारी वस्तुएं बन सकती हैं । यदि Impl
एंड्रयू के उदाहरण में वर्ग निजी था ( _Impl
), तो यह आपके उदाहरण के समान होगा। दूसरी ओर, सिंगलटन एक एंटीपैटर्न है और किसी को भी इसका उपयोग नहीं करना चाहिए।
Singelton._internal()
। आप तर्क दे सकते हैं कि सिंगलटन वर्ग के डेवलपर्स कई बार कक्षा को भी उकसा सकते हैं। यकीन है कि वहाँ Enum singelton है, लेकिन मेरे लिए यह केवल सैद्धांतिक उपयोग है। एक एनम एक एनम है, एक सिंगलटन नहीं ... जैसा कि शीर्ष-स्तरीय चर (@Andrew और @ सेठ) के उपयोग के लिए: क्या कोई भी शीर्ष-स्तरीय चर में नहीं लिख सकता है? यह किसी भी तरह से संरक्षित नहीं है, या मुझे कुछ याद नहीं है?
यहाँ एक और संभव तरीका है:
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;
}
उदाहरण के बाद ऑब्जेक्ट को परिवर्तित नहीं कर सकने वाला सिंगलटन
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}
संशोधित @Seth लड्डू उत्तर के लिए जो एकल की स्विफ्ट शैली पसंद करते हैं जैसे .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;
}
नमूना:
Auth.shared.username = 'abc';
सभी विकल्पों को पढ़ने के बाद मैं इसके साथ आया, जो मुझे एक "क्लासिक सिंगलटन" की याद दिलाता है:
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal();
static AccountService getInstance() {
return _instance;
}
}
getInstance
एक instance
संपत्ति में विधि static AccountService get instance => _instance;
यहां एक संक्षिप्त उदाहरण है जो अन्य समाधानों को जोड़ता है। सिंगलटन तक पहुँच कर किया जा सकता है:
singleton
वैश्विक चर का उपयोग करना जो उदाहरण की ओर इशारा करता है।Singleton.instance
पैटर्न।नोट: आपको केवल तीन विकल्पों में से एक को लागू करना चाहिए ताकि सिंगलटन का उपयोग करने वाला कोड सुसंगत हो।
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;
}
यदि आपको जटिल आरंभीकरण करने की आवश्यकता है, तो आपको प्रोग्राम में बाद में उदाहरण का उपयोग करने से पहले बस इतना करना होगा।
उदाहरण
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
}
हैलो, इस तरह से कुछ के बारे में क्या? बहुत सरल कार्यान्वयन, इंजेक्टर खुद सिंगलटन है और इसमें कक्षाएं भी जोड़ी हैं। बेशक बहुत आसानी से बढ़ाया जा सकता है। यदि आप इस पैकेज को और अधिक परिष्कृत जाँच के लिए देख रहे हैं: https://pub.dartlang.org/packages/flutter_simple_d 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;
}
}
यह काम करना चाहिए।
class GlobalStore {
static GlobalStore _instance;
static GlobalStore get instance {
if(_instance == null)
_instance = new GlobalStore()._();
return _instance;
}
_(){
}
factory GlobalStore()=> instance;
}
static GlobalStore get instance => _instance ??= new GlobalStore._();
करेंगे। क्या करना _(){}
चाहिए है? यह बेमानी लगता है।
जैसा कि मैं new
कीवर्ड या अन्य कंस्ट्रक्टर जैसे सिंगलेट्स पर कॉल का उपयोग करने का बहुत शौकीन नहीं हूं , मैं inst
उदाहरण के लिए स्टैटिक गेट्टर का उपयोग करना पसंद करूंगा :
// 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");
}
उदाहरण का उपयोग:
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));