आप डार्ट में एक सिंगलटन का निर्माण कैसे करते हैं?


203

सिंगलटन पैटर्न यह सुनिश्चित करता है कि किसी वर्ग का केवल एक उदाहरण कभी बनाया जाए। मैं इसे डार्ट में कैसे बनाऊं?


मैंने नीचे कई उत्तर देखे हैं जो एक वर्ग सिंगलटन बनाने के कई तरीकों का वर्णन करते हैं। इसलिए मैं सोच रहा हूं कि हम इस class_name ऑब्जेक्ट को पसंद क्यों नहीं करते हैं; if (ऑब्जेक्ट == null) रिटर्न ऑब्जेक्ट = new class_name; और वापसी वस्तु
अवनीश कुमार

जवाबों:


323

डार्ट के कारखाने के निर्माणकर्ताओं के लिए धन्यवाद , एक सिंगलटन का निर्माण करना आसान है:

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
}

2
हालाँकि दो बार इसे तत्काल करने की क्या बात है? जब आप दूसरी बार इसे इंस्टाल करते हैं तो यह एक त्रुटि नहीं होनी चाहिए?
पश्चिमोत्तर

53
मैं इसे दो बार तात्कालिक नहीं कर रहा हूं, बस एक सिंगलटन ऑब्जेक्ट का दो बार संदर्भ प्राप्त कर रहा हूं। आप शायद इसे वास्तविक जीवन में एक पंक्ति में दो बार नहीं करेंगे :) मुझे कोई अपवाद नहीं चाहिए, मैं हर बार एक ही सिंगलटन उदाहरण चाहता हूं जो मैं कहता हूं कि "नया सिंगलटन ()"। मैं मानता हूं, यह थोड़ा भ्रमित करने वाला है ... newइसका मतलब यह नहीं है कि "एक नया निर्माण" यहां, यह सिर्फ "कंस्ट्रक्टर को चलाने" का कहना है।
सेठ लड्ड

1
फैक्ट्री कीवर्ड वास्तव में यहाँ पर क्या करता है? यह विशुद्ध रूप से कार्यान्वयन की व्याख्या कर रहा है। इसकी आवश्यकता क्यों है?
13αrΚhικ

4
यह भ्रामक है कि आप एक निर्माता का उपयोग कर रहे हैं उदाहरण प्राप्त करने के लिए। newकीवर्ड पता चलता है कि वर्ग instantiated है, जो ऐसा नहीं है। मैं एक स्थिर विधि के लिए जाऊँगा get()या getInstance()जैसे मैं जावा में करता हूँ।
स्टीवन रोज

11
@SethLadd यह बहुत अच्छा है, लेकिन मेरा सुझाव है कि इसे स्पष्टीकरण के कुछ बिंदुओं की आवश्यकता है। अजीब सिंटैक्स है Singleton._internal();जो वास्तव में एक रचनाकार की परिभाषा के अनुसार एक विधि कॉल की तरह दिखता है। नहीं है _internalनाम। और निफ्टी भाषा का डिज़ाइन बिंदु है जिसे डार्ट आपको एक साधारण कंस्ट्रक्टर का उपयोग करके शुरू करने (डार्ट आउट) की अनुमति देता है और फिर, यदि आवश्यक हो, तो factoryसभी कॉलर्स को बदले बिना इसे एक विधि में बदल दें।
जेरी

170

यहाँ डार्ट में एक सिंगलटन बनाने के लिए कई अलग-अलग तरीकों की तुलना है।

1. कारखाना निर्माता

class SingletonOne {

  SingletonOne._privateConstructor();

  static final SingletonOne _instance = SingletonOne._privateConstructor();

  factory SingletonOne() {
    return _instance;
  }

}

2. गटर के साथ स्थिर क्षेत्र

class SingletonTwo {

  SingletonTwo._privateConstructor();

  static final SingletonTwo _instance = SingletonTwo._privateConstructor();

  static SingletonTwo get instance => _instance;
  
}

3. स्थैतिक क्षेत्र

class SingletonThree {

  SingletonThree._privateConstructor();

  static final SingletonThree instance = SingletonThree._privateConstructor();
  
}

कैसे उकसाया जाए

उपर्युक्त सिंग्नलों को इस तरह त्वरित किया जाता है:

SingletonOne one = SingletonOne();
SingletonTwo two = SingletonTwo.instance;
SingletonThree three = SingletonThree.instance;

ध्यान दें:

मैंने मूल रूप से इसे एक प्रश्न के रूप में पूछा था , लेकिन यह पता चला कि उपरोक्त सभी विधियां वैध हैं और चुनाव काफी हद तक व्यक्तिगत पसंद पर निर्भर करता है।


3
मैंने अभी आपके उत्तर को गलत बताया। स्वीकृत उत्तर की तुलना में बहुत अधिक स्पष्ट। बस एक और सवाल: दूसरे और तीसरे तरीके के लिए, निजी निर्माता का क्या कहना है? मैंने देखा कि बहुत से लोगों ने ऐसा किया है, लेकिन मुझे बात समझ में नहीं आती। मैं हमेशा बस उपयोग करता हूं static final SingletonThree instance = SingletonThree()। उसी के लिए दूसरा रास्ता जाता है _instance। मुझे नहीं पता कि निजी कंस्ट्रक्टर का उपयोग न करने का क्या नुकसान है। अब तक, मुझे अपने रास्ते में कोई समस्या नहीं है। दूसरे और तीसरे तरीके कॉल को डिफॉल्ट कंस्ट्रक्टर के लिए वैसे भी ब्लॉक नहीं कर रहे हैं।
sagon00

3
@ sagon00, प्राइवेट कंस्ट्रक्टर इतना है कि आप दूसरा उदाहरण नहीं बना सकते। अन्यथा कोई भी कर सकता था SingletonThree instance2 = SingletonThree()। यदि आप निजी कंस्ट्रक्टर होने पर ऐसा करने का प्रयास करते हैं, तो आपको यह त्रुटि The class 'SingletonThree' doesn't have a default constructor.
मिलेगी

40

मुझे यह पढ़ने में बहुत सहज नहीं लगता 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, एक टॉप लेवल गेटटर की जगह।

इसके अलावा बॉब निस्ट्रोम की टेक को उनके गेम प्रोग्रामिंग पैटर्न बुक से एकल पर पढ़ें ।


1
यह मेरे लिए और अधिक समझ में आता है, ग्रेग और डार्ट के शीर्ष-स्तरीय संपत्ति की विशेषता के लिए धन्यवाद।
पीआई

यह कोई मुहावरेदार नहीं है। भाषा में एक सिंगलटन पैटर्न का निर्माण करना एक स्वप्न की विशेषता है, और आप इसे बाहर फेंक रहे हैं क्योंकि आप इसके लिए अभ्यस्त नहीं हैं।
Arash

1
सेठ का उदाहरण और यह उदाहरण दोनों सिंगलटन पैटर्न हैं। यह वास्तव में वाक्य रचना "न्यू सिंगलटन ()" बनाम "सिंगलटन" का सवाल है। मुझे उत्तरार्द्ध अधिक स्पष्ट लगता है। डार्ट के कारखाने के निर्माता उपयोगी हैं, लेकिन मुझे नहीं लगता कि यह उनके लिए एक अच्छा उपयोग मामला है। मुझे यह भी लगता है कि डार्ट की आलसी प्रारंभिक विशेषता एक महान विशेषता है, जिसे कम किया जा रहा है। ऊपर बॉब का लेख भी पढ़ें - वह ज्यादातर मामलों में एकल के खिलाफ सिफारिश करता है।
ग्रेग लोवे

मैं भी मेलिंग सूची पर इस धागे को पढ़ने की सलाह देता हूं। group.google.com/a/dartlang.org/d/msg/misc/9dFnchCT4kA/…
ग्रेग लोव

यह तरीका बेहतर है। "नया" कीवर्ड बहुत अधिक नए ऑब्जेक्ट के निर्माण का अर्थ है। स्वीकृत समाधान वास्तव में गलत लगता है।
सावा बी

16

अपने पुस्तकालय के भीतर एक वैश्विक चर का उपयोग करने के बारे में क्या, जैसे?

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);
}

या इस पर भरोसा है?

जावा में सिंगलटन पैटर्न आवश्यक है, जहां ग्लोबल्स की अवधारणा मौजूद नहीं है, लेकिन ऐसा लगता है कि आपको डार्ट के आसपास लंबा रास्ता तय करने की आवश्यकता नहीं है।


5
शीर्ष-स्तरीय चर शांत हैं। हालाँकि, जो कोई भी। आयात कर सकता है, वह "नया इम्प्लांट ()" बनाने के लिए स्वतंत्र है। आप Impl को एक अंडरस्कोर कंस्ट्रक्टर दे सकते हैं, लेकिन तब सिंगलटन लाइब्रेरी के अंदर कोड उस कंस्ट्रक्टर को कॉल कर सकता है।
सेठ लड्डू

और आपके कार्यान्वयन में कोड नहीं कर सकते हैं? क्या आप अपने उत्तर में बता सकते हैं कि यह शीर्ष स्तर के चर से बेहतर क्यों है?
Jan

2
हाय @ जान, यह बेहतर या बुरा नहीं है, यह सिर्फ अलग है। एंड्रयू के उदाहरण में, Impl एक एकल वर्ग नहीं है। उदाहरण Singletonको एक्सेस करने में आसान बनाने के लिए उन्होंने शीर्ष-स्तरीय चर का सही उपयोग किया । ऊपर मेरे उदाहरण में, Singletonक्लास एक वास्तविक सिंगलटन है, Singletonआइसोलेट में कभी भी केवल एक ही उदाहरण मौजूद हो सकता है।
सेठ लड्डू

1
सेठ, तुम ठीक नहीं हो। नहीं है कोई वहाँ के रूप में एक वर्ग के instantiability प्रतिबंधित करने के कोई रास्ता नहीं है, डार्ट में जिस तरह से एक सच्चे सिंगलटन निर्माण करने के लिए अंदर की घोषणा पुस्तकालय। इसे हमेशा पुस्तकालय लेखक से अनुशासन की आवश्यकता होती है। आपके उदाहरण में, घोषित पुस्तकालय new Singleton._internal()जितनी बार चाहे उतनी बार कॉल कर सकता है, जिससे Singletonकक्षा की बहुत सारी वस्तुएं बन सकती हैं । यदि Implएंड्रयू के उदाहरण में वर्ग निजी था ( _Impl), तो यह आपके उदाहरण के समान होगा। दूसरी ओर, सिंगलटन एक एंटीपैटर्न है और किसी को भी इसका उपयोग नहीं करना चाहिए।
लडिसक सिप

@Ladicek, क्या आपको किसी लाइब्रेरी के डेवलपर्स पर भरोसा नहीं है कि वह नया फोन न करे Singelton._internal()। आप तर्क दे सकते हैं कि सिंगलटन वर्ग के डेवलपर्स कई बार कक्षा को भी उकसा सकते हैं। यकीन है कि वहाँ Enum singelton है, लेकिन मेरे लिए यह केवल सैद्धांतिक उपयोग है। एक एनम एक एनम है, एक सिंगलटन नहीं ... जैसा कि शीर्ष-स्तरीय चर (@Andrew और @ सेठ) के उपयोग के लिए: क्या कोई भी शीर्ष-स्तरीय चर में नहीं लिख सकता है? यह किसी भी तरह से संरक्षित नहीं है, या मुझे कुछ याद नहीं है?
टोबियास रिट्जाउ

12

यहाँ एक और संभव तरीका है:

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

11

कंस्ट्रक्टर और फैक्ट्री द्वारा डार्ट सिंगलटन

class Singleton {
  factory Singleton() =>
    const Singleton._internal_();
  const Singleton._internal_();
}


void main() {
  print(new Singleton() == new Singleton());
  print(identical(new Singleton() , new Singleton()));
}

5

उदाहरण के बाद ऑब्जेक्ट को परिवर्तित नहीं कर सकने वाला सिंगलटन

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}

4

संशोधित @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';

4

सभी विकल्पों को पढ़ने के बाद मैं इसके साथ आया, जो मुझे एक "क्लासिक सिंगलटन" की याद दिलाता है:

class AccountService {
  static final _instance = AccountService._internal();

  AccountService._internal();

  static AccountService getInstance() {
    return _instance;
  }
}

3
मैं इस तरह से getInstanceएक instanceसंपत्ति में विधि static AccountService get instance => _instance;
बदलूंगा

यह मुझे पंसद है। चूँकि मैं किसी चीज़ को जोड़ने से पहले उदाहरण वापस चाहता हूँ और अन्य विधियों का उपयोग किया जाता है।
चिटगोक

4

यहाँ एक सरल जवाब है:

class Singleton {
  static Singleton _instance;

  Singleton._();

  static Singleton get getInstance => _instance = _instance ?? Singleton._();
}

3

यहां एक संक्षिप्त उदाहरण है जो अन्य समाधानों को जोड़ता है। सिंगलटन तक पहुँच कर किया जा सकता है:

  • एक 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
}

1

हैलो, इस तरह से कुछ के बारे में क्या? बहुत सरल कार्यान्वयन, इंजेक्टर खुद सिंगलटन है और इसमें कक्षाएं भी जोड़ी हैं। बेशक बहुत आसानी से बढ़ाया जा सकता है। यदि आप इस पैकेज को और अधिक परिष्कृत जाँच के लिए देख रहे हैं: 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;
  }
}

0

यह काम करना चाहिए।

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._();करेंगे। क्या करना _(){}चाहिए है? यह बेमानी लगता है।
गुंटर ज़ोचबॉयर

क्षमा करें, यह एक सुझाव था, अनुवर्ती प्रश्न नहीं, _ () {} एक निजी निर्माणकर्ता का अधिकार बनाएगा?
दिलशाद पीपी

निर्माता वर्ग के नाम से शुरू होते हैं। यह निर्दिष्ट रिटर्न प्रकार के बिना सिर्फ एक सामान्य निजी इंस्टेंस विधि है।
गुंटर ज़ोचबॉयर

1
डाउनवोट के लिए क्षमा करें, लेकिन मुझे लगता है कि यह खराब गुणवत्ता का है और मौजूदा उत्तरों के अतिरिक्त कोई मूल्य नहीं जोड़ता है।
गुंटर ज़ोचबॉयर

2
हालांकि यह कोड प्रश्न का उत्तर दे सकता है, लेकिन यह समस्या का हल कैसे और / या इसके बारे में अतिरिक्त संदर्भ प्रदान करता है, इससे उत्तर के दीर्घकालिक मूल्य में सुधार होगा।
कार्ल रिक्टर

0

जैसा कि मैं 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));
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.