I've often found myself having to use annoying patterns like:
ClassA extends BaseClass {
static bool is(val) { ... }
}
ClassB extends BaseClass {
static bool is(val) { ... }
}
...
ClassZ extends BaseClass {
static bool is(val) { ... }
}
BaseClass parser(val) {
if(ClassA.is(val)) {
return ClassA(val);
} else if(ClassB.is(val)) {
return ClassB(val);
...
} else if(ClassZ.is(val)) {
return ClassB(val);
}
}
This is very error prone and requires a lot of monotonous code.
I was wondering if there was a way to expedite this process in a non-language specific (or in a language specific for Dart) way that doesn't involve listing all the pattern matchers after they've been defined. I would like to avoid this as I had too many bugs to count caused by forgetting to list one of the already defined class's pattern matcher.
If you want to cut down the arbitrary conditionals in the BaseClass.parser(), you can use a map as follows:
typedef Specification = bool Function(dynamic val);
typedef Factory = BaseClass Function(dynamic val);
class BaseClass
{
static final Map<Specification, Factory> _factoryMap = {
(val) => val == 'Hello': (val) => ClassA(),
(val) => val == 'There': (val) => ClassB(),
};
static BaseClass? parse(dynamic val)
{
for(var key in _factoryMap.keys)
{
if(key(val)) return _factoryMap[key]!.call(val);
}
throw ArgumentError('No valid factory found!');
}
}
class ClassA extends BaseClass
{ }
class ClassB extends BaseClass
{ }
class ClassC extends BaseClass
{ }
In Python, you can extend type and register the subclass's own specification method without manually listing like this. But I am not aware of such runtime meta programming in Dart for the time being. Maybe you can use source_gen in Dart to generate the conditionals automatically.
Combining the check with the construction of the object would help slightly. That would reduce the potential of accidentally using the wrong check and constructor, and it would reduce the amount of code you'd need to add outside of the class definitions:
ClassA extends BaseClass {
/// Attempts to return a [ClassA] if possible.
///
/// Returns `null` if inappropriate.
static ClassA? tryFrom(dynamic val) { ... }
}
ClassB extends BaseClass {
static ClassB? tryFrom(dynamic val) { ... }
}
...
ClassZ extends BaseClass {
static ClassZ? tryFrom(dynamic val) { ... }
}
BaseClass parser(dynamic val) {
BaseClass object = ClassA.tryFrom(val) ??
ClassB.tryFrom(val) ??
... ??
ClassZ.tryFrom(val);
if (object == null) {
// Throw some exception here.
}
return object;
}
from there, you can make parser use a loop:
typedef TryFromFunction = BaseClass? Function(dynamic);
final tryFromFunctions = [
ClassA.tryFrom,
ClassB.tryFrom,
...
ClassZ.tryFrom,
];
BaseClass parser(dynamic val) {
for (var tryFrom in tryFromFunctions) {
var object = tryFrom(val);
if (object != null) {
return object;
}
}
// Throw some exception here.
}
That wouldn't absolve you of the responsibility of updating some other location whenever a new class is added, but:
The work would be minimal.
You maybe could add unit tests to check that the list is updated. For example, if each of ClassA, ClassB, ..., ClassZ is in a separate file easily distinguished by path or filename, then you could have a test that verifies that tryFromFunctions.length matches the number of those files.
For now, I've used a solution that takes from the others listed and adds a twist. Basically, I create a list of matchers like the others but do the work of adding the matcher in the class itself. Basically,
List<BaseClass Function(dynamic)> _matchers = [];
bool addMatcher(bool Function(dynamic) matcher, BaseClass Function(dynamic) factory) {
_matchers.add((val) {
return matcher(val) ? factory(val) : null;
});
return true;
}
class ClassA extends BaseClass {
static final _ = addMatcher(matches, (val) => ClassA(val));
ClassA(val) { ... }
static bool matches(val) { ... }
}
class ClassB extends BaseClass {
static final _ = addMatcher(...);
...
}
...
BaseClass parser(val) {
for (var matcher in _matchers) {
var object = matcher(val);
if (object != null) {
return object;
}
}
// Throw some exception here.
}
The rational behind this is that I can easily verify that the class is being checked. Unfortunately I'm still not sure how to do this automatically since this was just a quick and dirty solution. I may come back to this with an update if I end up implementing source generation or unit tests for automatic generation/verification.
I want to create a thread-safe singleton instance for my vala class.
As you know, singletons may lead to threading issues if not properly implemented.
Also you can use SingleInstance Code Attribute. It does the same for you automatically!
[SingleInstance]
public class ExampleClass : Object {
public int prop { get; set; default = 42; }
public ExampleClass () {
// ...
}
}
int main (string[] args) {
var a = new ExampleClass (); // the two refs
var b = new ExampleClass (); // are the same
b.prop += 1;
assert (a.prop == b.prop);
return 0;
}
Note, that in this case you don't need to call a static function like instance() or get_instance(). Simply creating an object via new will give you a reference to the singleton.
The recommended way is to use the GLib.Once construct:
public class MyClass : Object {
private static GLib.Once<MyClass> _instance;
public static unowned MyClass instance () {
return _instance.once (() => { return new MyClass (); });
}
}
I was wondering if is possible to create an instance of a generic type in Dart. In other languages like Java you could work around this using reflection, but I'm not sure if this is possible in Dart.
I have this class:
class GenericController <T extends RequestHandler> {
void processRequest() {
T t = new T(); // ERROR
}
}
I tried mezonis approach with the Activator and it works. But it is an expensive approach as it uses mirrors, which requires you to use "mirrorsUsed" if you don't want to have a 2-4MB js file.
This morning I had the idea to use a generic typedef as generator and thus get rid of reflection:
You define a method type like this: (Add params if necessary)
typedef S ItemCreator<S>();
or even better:
typedef ItemCreator<S> = S Function();
Then in the class that needs to create the new instances:
class PagedListData<T>{
...
ItemCreator<T> creator;
PagedListData(ItemCreator<T> this.creator) {
}
void performMagic() {
T item = creator();
...
}
}
Then you can instantiate the PagedList like this:
PagedListData<UserListItem> users
= new PagedListData<UserListItem>(()=> new UserListItem());
You don't lose the advantage of using generic because at declaration time you need to provide the target class anyway, so defining the creator method doesn't hurt.
You can use similar code:
import "dart:mirrors";
void main() {
var controller = new GenericController<Foo>();
controller.processRequest();
}
class GenericController<T extends RequestHandler> {
void processRequest() {
//T t = new T();
T t = Activator.createInstance(T);
t.tellAboutHimself();
}
}
class Foo extends RequestHandler {
void tellAboutHimself() {
print("Hello, I am 'Foo'");
}
}
abstract class RequestHandler {
void tellAboutHimself();
}
class Activator {
static createInstance(Type type, [Symbol constructor, List
arguments, Map<Symbol, dynamic> namedArguments]) {
if (type == null) {
throw new ArgumentError("type: $type");
}
if (constructor == null) {
constructor = const Symbol("");
}
if (arguments == null) {
arguments = const [];
}
var typeMirror = reflectType(type);
if (typeMirror is ClassMirror) {
return typeMirror.newInstance(constructor, arguments,
namedArguments).reflectee;
} else {
throw new ArgumentError("Cannot create the instance of the type '$type'.");
}
}
}
I don't know if this is still useful to anyone. But I have found an easy workaround. In the function you want to initialize the type T, pass an extra argument of type T Function(). This function should return an instance of T. Now whenever you want to create object of T, call the function.
class foo<T> {
void foo(T Function() creator) {
final t = creator();
// use t
}
}
P.S. inspired by Patrick's answer
2022 answer
Just came across this problem and found out that although instantiating using T() is still not possible, you can get the constructor of an object easier with SomeClass.new in dart>=2.15.
So what you could do is:
class MyClass<T> {
final T Function() creator;
MyClass(this.creator);
T getGenericInstance() {
return creator();
}
}
and when using it:
final myClass = MyClass<SomeOtherClass>(SomeOtherClass.new)
Nothing different but looks cleaner imo.
Here's my work around for this sad limitation
class RequestHandler {
static final _constructors = {
RequestHandler: () => RequestHandler(),
RequestHandler2: () => RequestHandler2(),
};
static RequestHandler create(Type type) {
return _constructors[type]();
}
}
class RequestHandler2 extends RequestHandler {}
class GenericController<T extends RequestHandler> {
void processRequest() {
//T t = new T(); // ERROR
T t = RequestHandler.create(T);
}
}
test() {
final controller = GenericController<RequestHandler2>();
controller.processRequest();
}
Sorry but as far as I know, a type parameter cannot be used to name a constructor in an instance creation expression in Dart.
Working with FLutter
typedef S ItemCreator<S>();
mixin SharedExtension<T> {
T getSPData(ItemCreator<T> creator) async {
return creator();
}
}
Abc a = sharedObj.getSPData(()=> Abc());
P.S. inspired by Patrick
simple like that.
import 'dart:mirrors';
void main(List<String> args) {
final a = A<B>();
final b1 = a.getInstance();
final b2 = a.getInstance();
print('${b1.value}|${b1.text}|${b1.hashCode}');
print('${b2.value}|${b2.text}|${b2.hashCode}');
}
class A<T extends B> {
static int count = 0;
T getInstance() {
return reflectClass(T).newInstance(
Symbol(''),
['Text ${++count}'],
{Symbol('value'): count},
).reflectee;
}
}
class B {
final int value;
final String text;
B(this.text, {required this.value});
}
Inspired by Patrick's answer, this is the factory I ended up with.
class ServiceFactory<T> {
static final Map<Type, dynamic> _cache = <String, dynamic>{};
static T getInstance<T>(T Function() creator) {
String typeName = T.toString();
return _cache.putIfAbsent(typeName, () => creator());
}
}
Then I would use it like this.
final authClient = ServiceFactory.getInstance<AuthenticationClient>(() => AuthenticationClient());
Warning: Erik made a very good point in the comment below that the same type name can exist in multiple packages and that will cause issues. As much as I dislike to force the user to pass in a string key (that way it's the consumer's responsibility to ensuring the uniqueness of the type name), that might be the only way.
Basically, that's what I'm trying to do:
ClassName
{
final OtherClass field;
ClassName()
{
field = new OtherClass(this);
}
}
It's not possible to assign a final field in a constructor body. The final field needs to be assigned before the constructor body, in the initializer list or on declaration:
class ClassName
{
final OtherClass field = new OtherClass(); // Here
ClassName()
: field = new OtherClass() // or here
{
}
}
As you can't use this in the initializer list or on the declaration, you can't do what you plan to do.
With null safety, you can initialize a final field in different ways:
At declaration:
class Foo{
final int bar = 1;
}
In constructor parameter (initializing formal).
class Foo {
final int bar;
// Initializing in constructor parameter.
Foo(this.bar);
}
In the initializer list.
class Foo {
final int bar;
// Initializer list
Foo() : bar = 1;
}
Combination of above two.
class Foo {
final int bar;
Foo(int value) : bar = value;
}
Use late keyword for lazy initialization.
class Foo {
late final int bar; // Initialize it later, maybe in a method
}
Since Dart 2.12 it is possible by using late keyword.
The code below prints 5:
class ClassName
{
final int var1 = 5;
late final OtherClass field;
ClassName()
{
field = new OtherClass(this);
}
}
class OtherClass {
OtherClass(ClassName object) {
print(object.var1);
}
}
void main() {
final object = ClassName();
}
Please see this and the following sections
The singleton pattern ensures only one instance of a class is ever created. How do I build this in Dart?
Thanks to Dart's factory constructors, it's easy to build a singleton:
class Singleton {
static final Singleton _singleton = Singleton._internal();
factory Singleton() {
return _singleton;
}
Singleton._internal();
}
You can construct it like this
main() {
var s1 = Singleton();
var s2 = Singleton();
print(identical(s1, s2)); // true
print(s1 == s2); // true
}
Here is a comparison of several different ways to create a singleton in Dart.
1. Factory constructor
class SingletonOne {
SingletonOne._privateConstructor();
static final SingletonOne _instance = SingletonOne._privateConstructor();
factory SingletonOne() {
return _instance;
}
}
2. Static field with getter
class SingletonTwo {
SingletonTwo._privateConstructor();
static final SingletonTwo _instance = SingletonTwo._privateConstructor();
static SingletonTwo get instance => _instance;
}
3. Static field
class SingletonThree {
SingletonThree._privateConstructor();
static final SingletonThree instance = SingletonThree._privateConstructor();
}
How to instantiate
The above singletons are instantiated like this:
SingletonOne one = SingletonOne();
SingletonTwo two = SingletonTwo.instance;
SingletonThree three = SingletonThree.instance;
Note:
I originally asked this as a question, but discovered that all of the methods above are valid and the choice largely depends on personal preference.
Here is a simple answer:
Class should have a private and static property of its type.
The constructor should be private to prevent external object initialization.
Check if the instance is null, if yes create an instance and return it, otherwise return the existing instance.
Implementation (Lazy Loading)
class Singleton {
static Singleton? _instance;
Singleton._();
static Singleton get instance => _instance ??= Singleton._();
void someMethod(){
...
}
...
}
Implementation (Eager Loading)
class Singleton {
static Singleton _instance = Singleton._();
Singleton._();
static Singleton get instance => _instance;
void someMethod(){
...
}
...
}
Usage
Singleton.instance.someMethod();
I don't find it very intuitive reading new Singleton(). You have to read the docs to know that new isn't actually creating a new instance, as it normally would.
Here's another way to do singletons (Basically what Andrew said above).
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();
}
Note that the singleton doesn't get created until the first time the getter is called due to Dart's lazy initialization.
If you prefer you can also implement singletons as static getter on the singleton class. i.e. Thing.singleton, instead of a top level getter.
Also read Bob Nystrom's take on singletons from his Game programming patterns book.
What about just using a global variable within your library, like so?
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);
}
Or is this frowned upon?
The singleton pattern is necessary in Java where the concept of globals doesn't exist, but it seems like you shouldn't need to go the long way around in Dart.
Here is another possible way:
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;
}
Singleton that can't change the object after the instantiation
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, age: 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}
Dart singleton by const constructor & factory
class Singleton {
factory Singleton() =>
Singleton._internal_();
Singleton._internal_();
}
void main() {
print(new Singleton() == new Singleton());
print(identical(new Singleton() , new Singleton()));
}
In this example I do other things that are also necessary when wanting to use a Singleton. For instance:
pass a value to the singleton's constructor
initialize a value inside the constructor itself
set a value to a Singleton's variable
be able to access AND access those values.
Like this:
class MySingleton {
static final MySingleton _singleton = MySingleton._internal();
String _valueToBeSet;
String _valueAlreadyInSingleton;
String _passedValueInContructor;
get getValueToBeSet => _valueToBeSet;
get getValueAlreadyInSingleton => _valueAlreadyInSingleton;
get getPassedValueInConstructor => _passedValueInContructor;
void setValue(newValue) {
_valueToBeSet = newValue;
}
factory MySingleton(String passedString) {
_singleton._valueAlreadyInSingleton = "foo";
_singleton._passedValueInContructor = passedString;
return _singleton;
}
MySingleton._internal();
}
Usage of MySingleton:
void main() {
MySingleton mySingleton = MySingleton("passedString");
mySingleton.setValue("setValue");
print(mySingleton.getPassedValueInConstructor);
print(mySingleton.getValueToBeSet);
print(mySingleton.getValueAlreadyInSingleton);
}
After reading all the alternatives I came up with this, which reminds me a "classic singleton":
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal();
static AccountService getInstance() {
return _instance;
}
}
Since Dart 2.13 version, it is very easy with late keyword. Late keyword allows us to lazily instantiate objects.
As an example, you can see it:
class LazySingletonExample {
LazySingletonExample._() {
print('instance created.');
}
static late final LazySingletonExample instance = LazySingletonExample._();
}
Note: Keep in mind that, it will only be instantiated once when you call lazy instance field.
Here's a concise example that combines the other solutions. Accessing the singleton can be done by:
Using a singleton global variable that points to the instance.
The common Singleton.instance pattern.
Using the default constructor, which is a factory that returns the instance.
Note: You should implement only one of the three options so that code using the singleton is consistent.
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;
}
If you need to do complex initialization, you'll just have to do so before using the instance later in the program.
Example
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
}
This is how I implement singleton in my projects
Inspired from flutter firebase => FirebaseFirestore.instance.collection('collectionName')
class FooAPI {
foo() {
// some async func to api
}
}
class SingletonService {
FooAPI _fooAPI;
static final SingletonService _instance = SingletonService._internal();
static SingletonService instance = SingletonService();
factory SingletonService() {
return _instance;
}
SingletonService._internal() {
// TODO: add init logic if needed
// FOR EXAMPLE API parameters
}
void foo() async {
await _fooAPI.foo();
}
}
void main(){
SingletonService.instance.foo();
}
example from my project
class FirebaseLessonRepository implements LessonRepository {
FirebaseLessonRepository._internal();
static final _instance = FirebaseLessonRepository._internal();
static final instance = FirebaseLessonRepository();
factory FirebaseLessonRepository() => _instance;
var lessonsCollection = fb.firestore().collection('lessons');
// ... other code for crud etc ...
}
// then in my widgets
FirebaseLessonRepository.instance.someMethod(someParams);
Modified #Seth Ladd answer for who's prefer Swift style of singleton like .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;
}
Sample:
Auth.shared.username = 'abc';
If you happen to be using Flutter and provider package for state management, creating and using a singleton is quite straightforward.
Create an instance
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => SomeModel()),
Provider(create: (context) => SomeClassToBeUsedAsSingleton()),
],
child: MyApp(),
),
);
}
Get the instance
Widget build(BuildContext context) {
var instance = Provider.of<SomeClassToBeUsedAsSingleton>(context);
...
** Sigleton Paradigm in Dart Sound Null Safety**
This code snippet shows how to implement singleton in dart
This is generally used in those situation in which we have to use same object of a class every time for eg. in Database transactions.
class MySingleton {
static MySingleton? _instance;
MySingleton._internal();
factory MySingleton() {
if (_instance == null) {
_instance = MySingleton._internal();
}
return _instance!;
}
}
Singleton objects can be betterly created with null safety operator and factory constructor.
class Singleton {
static Singleton? _instance;
Singleton._internal();
factory Singleton() => _instance ??= Singleton._internal();
void someMethod() {
print("someMethod Called");
}
}
Usage:
void main() {
Singleton object = Singleton();
object.someMethod(); /// Output: someMethod Called
}
Note: ?? is a Null aware operator, it returns the right-side value if the left-side value is null, which means in our example _instance ?? Singleton._internal();, Singleton._internal() will be return first time when object gets called , rest _instance will be return.
how to create a singleton instance of a class in dart flutter
class ContactBook {
ContactBook._sharedInstance();
static final ContactBook _shared = ContactBook._sharedInstance();
factory ContactBook() => _shared;
}
This is my way of doing singleton which accepts parameters (you can paste this directly on https://dartpad.dev/ ):
void main() {
Logger x = Logger('asd');
Logger y = Logger('xyz');
x.display('Hello');
y.display('Hello There');
}
class Logger{
Logger._(this.message);
final String message;
static Logger _instance = Logger._('??!?*');
factory Logger(String message){
if(_instance.message=='??!?*'){
_instance = Logger._(message);
}
return _instance;
}
void display(String prefix){
print(prefix+' '+message);
}
}
Which inputs:
Hello asd
Hello There asd
The '??!?*' you see is just a workaround I made to initialize the _instance variable temporarily without making it a Logger? type (null safety).
This should work.
class GlobalStore {
static GlobalStore _instance;
static GlobalStore get instance {
if(_instance == null)
_instance = new GlobalStore()._();
return _instance;
}
_(){
}
factory GlobalStore()=> instance;
}
As I'm not very fond of using the new keyword or other constructor like calls on singletons, I would prefer to use a static getter called inst for example:
// 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");
}
example usage:
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));
Hello what about something like this? Very simple implementation, Injector itself is singleton and also added classes into it. Of course can be extended very easily. If you are looking for something more sophisticated check this package: https://pub.dartlang.org/packages/flutter_simple_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;
}
}
I use this simple pattern on dart and previously on Swift. I like that it's terse and only one way of using it.
class Singleton {
static Singleton shared = Singleton._init();
Singleton._init() {
// init work here
}
void doSomething() {
}
}
Singleton.shared.doSomething();
This is also a way to create a Singleton class
class Singleton{
Singleton._();
static final Singleton db = Singleton._();
}
Create Singleton
class PermissionSettingService {
static PermissionSettingService _singleton = PermissionSettingService._internal();
factory PermissionSettingService() {
return _singleton;
}
PermissionSettingService._internal();
}
Reset Singleton
// add this function inside the function
void reset() {
_singleton = PermissionSettingService._internal();
}
There is nothing tricky about creating a Singleton in Dart. You can declare any variable in a top-level (global) location, which is a Singleton by default. You can also declare a variable as a static member of a class. This is a singleton A.
class A {}
final a = A();
However, the above does not allow you to replace the instance for testing. The other issue is that as the app grows in complexity, you may want to convert global or static variables to transient dependencies inside your classes. If you use dependency injection, you can change a dependency inside your composition at any time. This is an example of using ioc_container to configure a singleton instance of A in the root of an app. You can change this to a transient dependency any time by using add instead of addSingletonService
import 'package:ioc_container/ioc_container.dart';
class A {}
void main(List<String> arguments) {
final builder = IocContainerBuilder()..addSingletonService(A());
final container = builder.toContainer();
final a1 = container<A>();
final a2 = container<A>();
print(identical(a1, a2));
}
The above prints true because the app will only ever mint one instance of A.
You can just use the Constant constructors.
class Singleton {
const Singleton(); //Constant constructor
void hello() { print('Hello world'); }
}
Example:
Singleton s = const Singleton();
s.hello(); //Hello world
According with documentation:
Constant constructors
If your class produces objects that never change, you can make these objects compile-time constants. To do this, define a const constructor and make sure that all instance variables are final.