Skip to content

Instantly share code, notes, and snippets.

@theburningmonk
Last active September 2, 2022 01:40
Show Gist options
  • Save theburningmonk/6401183 to your computer and use it in GitHub Desktop.
Save theburningmonk/6401183 to your computer and use it in GitHub Desktop.
Using Dart's factory constructor feature to implement the singleton pattern
class MyClass {
static final MyClass _singleton = new MyClass._internal();
factory MyClass() {
return _singleton;
}
MyClass._internal() {
... // initialization logic here
}
... // rest of the class
}
// consuming code
MyClass myObj = new MyClass(); // get back the singleton
...
// another piece of consuming code
MyClass myObj = new MyClass(); // still getting back the singleton
@Allan-Nava
Copy link

How can I pass a parameter to this class?

@developerpaaji
Copy link

Nice

@developerpaaji
Copy link

How can I pass a parameter to this class?

I think by getting parameters from factory and passing them in internal class

@StephanCassel
Copy link

Thump up.
Clean and simple.

@moda20
Copy link

moda20 commented Apr 20, 2019

Can anybody show us the code when using parameters ?

@wyattbiker
Copy link

Something like this maybe passing the parameter to the MyClass() constructor. MyClass._internal() is called only once after the constructor sets start class variable.

class MyClass {
  num instanceVar;
  static num start;
  static final MyClass _singleton = new MyClass._internal();

  factory MyClass(num startparam) {
    start = startparam;
    return _singleton;
  }

  MyClass._internal() {
    if (instanceVar == null) {
      instanceVar = start;
    } else {
      instanceVar++;
    }
  }

  // rest of the class
}

main() {
// consuming code
  MyClass myObj1 = MyClass(1); // get back the singleton
  print('myObj1=${myObj1.instanceVar}');

// another piece of consuming code
  MyClass myObj2 = MyClass(2); // still getting back the singleton
  print('myObj2=${myObj2.instanceVar}');
}

@mkobuolys
Copy link

For those, who are asking how to pass parameters to the class - probably, you are mixing something there. Singleton design pattern is intended to create one and only one (single) instance of a class. So if you want to pass parameters, probably, you want to create a different kind of object - that's not what singleton design pattern used for. Please, consider this and check your code to understand if you need a singleton there, maybe you just need to use a different design pattern, e.g. factory method or abstract factory.

@ascmp
Copy link

ascmp commented Oct 25, 2019

@MangirdasKazlauskas I hear you, but I can't figure out the proper way to accomplish what I want. I've an AppConfig class, which contains only read only params like appName and so on, and I want that to be accessible from anywhere in the code, so I can do something like AppConfig().appName which is read only. Therefore the singleton sounds like a proper paradigm to me. But now I've 3 flavors, as I'm trying to implement a white label app, and for each flavor appName will have a different value (say "One", "Two", and "Three"). Therefore the need to control my singleton with a parameter, which like you say feels wrong - I implemented it and it works but it still feels wrong, because either somehow I need to make sure something is called before the singleton is initialized (wrong) or I can initialize it on demand so every time I call it (and in this case it feels weird that all the following passed params will be ignored). I tried also the factory approach, which seems awkward at least and it's just another variation of the same class I have. Any idea where my problem is?

@DiplNext
Copy link

DiplNext commented Dec 7, 2019

how can I use that as global class with getters, setters, constructors variables... ?

@aleor
Copy link

aleor commented Mar 10, 2020

@ascmp Trying to solve exactly the same problem with AppConfig as a singleton using params from relevant json files.
Have you found any elegant solutions?..

@matsp
Copy link

matsp commented Mar 23, 2020

I actually came up with something like this:

import 'dart:async';

import 'package:rxdart/rxdart.dart';
import 'package:example/app_config.dart';

class ApplicationConfigurationService {
  static final ApplicationConfigurationService _instance =
      ApplicationConfigurationService._singelton();

  static final _behaviorSubject = BehaviorSubject<AppConfig>();
  final StreamSink<AppConfig> configStreamSink = _behaviorSubject.sink;
  final Stream<AppConfig> configStream = _behaviorSubject.stream;

  factory ApplicationConfigurationService() => _instance;

  ApplicationConfigurationService._singelton();
}

I am writing a command-line program and in the main.dart I'am writing on the StreamSink of my AppConfigService after parsing my JSON file. Due the service is using a BehaviorSubject the last value will be cached and replayed to new subscribers / listeners.

Later when I need the config values I do the following:

final applicationConfigurationService = ApplicationConfigurationService();
...
applicationConfigurationService.configStream.first.then((config) {
      _appConfig = config;
});

Or if you want you can even react to config changes when you need that feature.

@ronscoder
Copy link

I think, one could use the static instance variable also.
MyClass myObj1 = MyClass._singleton; // get back the singleton

@danielgomezrico
Copy link

This feels like an antipattern, singleton should be implemented with a private constructor and a static singleton class.
Having a constructor that returns the singleton on behind hides this detail from the developer.

@bsutton
Copy link

bsutton commented Feb 5, 2021

The pattern proposed by @theburningmonk actually has a problem.

I just spent twenty minutes chasing down a bug which this pattern obscured.

The problem was that my _internal method was throwing an exception.
In the exception handler I was trying to reference the same factory instance. This caused an npe as _singleton was null (due to the _internal exception) so I got an npe rather than the original exception.

The following pattern avoids this issue:

class MyClass {
  static  MyClass _singleton;

  factory MyClass() => _singleton ??= MyClass._internal();

  MyClass._internal() {
    ... // initialization logic here
  }

  ... // rest of the class
}

The only disadvantage is that _singleton can no longer be final.

@icnahom
Copy link

icnahom commented Oct 5, 2021

Singleton design pattern is intended to create one and only one (single) instance of a class.

If you wanted a single instance with a parameter, how would you do that?

Do you see any issue in this code?

class MyClass  {
  MyClass._(this.parameter);
  final String parameter;

  static MyClass? _instance;

  static void initialize(String parameter) {
    _instance = MyClass._(parameter );
  }

  static MyClass get instance => _instance!; // throw an "initialize first" error

  // access parameter 
}

@elbeicktalat
Copy link

Singleton design pattern is intended to create one and only one (single) instance of a class.

If you wanted a single instance with a parameter, how would you do that?

Do you see any issue in this code?
This is not a singleton implementation.

See this for reference: Dart Null-Safty Singleton with parameters

@srihari9n
Copy link

Can MyClass extend an abstract class with non-null constructor? If so how?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment