In Dart, is it possible to pass an argument in a singleton?
Asked Answered
U

6

28
class Peoples {
  late int id;
  late String name;

  static final Peoples _inst = Peoples._internal();

  Peoples._internal();

  factory Peoples() {
    return _inst;
  }
}

I have this singleton class. Which ensures that, only one instance of a class is ever created. So, even if someone tries to instantiate it, they will use the same instance. And i can create and set values, like:

  Peoples ps1 = Peoples();
  Peoples ps2 = Peoples();

  ps1.id = 1;
  ps1.name = "First";

  ps2.id = 2;
  ps2.name = "Second";

Is it possible to instantiate and set values like:

  Peoples ps1 = Peoples(1, "First");
  Peoples ps2 = Peoples(2, "Second");

So, now both "ps1" and "ps2" will have (2, "Second").

Undeniable answered 11/5, 2019 at 8:45 Comment(0)
E
56

Sure! You need to pass the arguments to the factory method then you need to update the properties USING the referenced instance.

For example, you had

class Peoples {
  late int id;
  late String name;

  static final Peoples _inst = Peoples._internal();

  Peoples._internal();

  factory Peoples() {
    return _inst;
  }
}

If you apply my solution then you have

class Peoples {
  late int id;
  late String name;

  static final Peoples _inst = Peoples._internal();

  Peoples._internal();

  factory Peoples({int id, String name}) {
    _inst.id = id
    _inst.name = name
    return _inst;
  }
}

with this your question should be answered for more info about factory and params visit

https://dart.dev/guides/language/language-tour

Working Example

class Peoples {
  late int id;
  late String name;

  static final Peoples _inst = Peoples._internal();

  Peoples._internal();
  

  factory Peoples(int id, String name) {
    _inst.id = id;
    _inst.name = name;
    return _inst;
  }
}

void main() {
  print("Instance of = " + Peoples(0, "Dylan").name);
  print("Instance of = " + Peoples(1, "Joe").name);
  print("Instance of = " + Peoples(2, "Maria").name);
}
Ern answered 11/5, 2019 at 9:14 Comment(1)
Is there any way to do this with final int id and final String name ?Necktie
W
4

I'd like to answer showing a way to create a singleton by passing arguments to it and how to "lock" its values after creating it for the first time.

class People {
  static final People _inst = People._internal();
  People._internal();

  factory People(int id, String name) {
    assert(!_inst._lock, "it's a singleton that can't re-defined");
    _inst.id = id;
    _inst.name = name;
    _inst._lock = true;
    return _inst;
  }
  
  int id;
  String name;
  bool _lock = false;
}

void main() {
  var people = People(0, 'Dylan');
  try{
    print('Instance of = ' + People(0, 'Joe').name);
    print('Instance of = ' + People(1, 'Maria').name);
    print('Instance of = ' + People(2, 'Ete sech').name);
  } finally {
    print('Instance of = ' + people.name);
  }
}
Withdrew answered 26/10, 2020 at 5:10 Comment(3)
kind of a weird example, How about I would like to pass in a list of valid people how would that look like. I struggle with getting that use model working.Adult
Well, for this context this model could be useless, but think in a singleton where you want to save info that you won't modify, it will just be read. It's like when you want to save an user after app started and you don't want to use shared preference or the cloud to hold and request about its info. I thought it would be useful.Carcanet
Assert only works in debugging mode. So, it would still reassign those values in production mode.Deonnadeonne
G
3

Dart / Flutter Singleton With Arguments That Cannot Be Changed

This is an instance of a class that will always be returned the same after its first construction.

The class fields are not final or late, but rather are nullable.

  • The factory constructor will only allow instance variables to change if they are null.
  • The factory constructor provides default values to the instance variables if they are not provided.
class SingletonClass {
  bool? debugMode;

  /// Always return a singleton instance
  static final SingletonClass _instance = SingletonClass._internal();

  /// Internal Constructor
  SingletonClass._internal();

  /// Consumable Constructor
  factory SingletonClass({bool debugMode = false}) {
    // Set null class parameters
    _instance.debugMode ??= debugMode;

    return _instance;
  }
}
// Initialize the singleton
SingletonClass singletonClass = SingletonClass(debugMode: true);
debugPrint("debugMode: ${singletonClass.debugMode}");

/// Attempt to create another instance with different arguments / field values
SingletonClass singletonClass2 = SingletonClass(debugMode: false);
debugPrint("debugMode2: ${singletonClass2.debugMode}");

Console log output

flutter: debugMode: true
flutter: debugMode2: true

The debugMode remains true even though the second attempt at creating the class declares it false. The same instance of the class is returned for both singletonClass and singletonClass2.

You may declare a new SingletonClass type variable anywhere in your code you need access to its parameters and it will be the same.

Gospel answered 20/11, 2022 at 13:31 Comment(0)
H
1

The answer can not run on my machine, 29/3/2022

The computer says: “Non-nullable instance field 'id' must be initialized.”

I cannot comment, so write this answer:

Add keyword late before the member variables will help:

class Peoples {
  late int id;
  late String name;

  static final Peoples _inst = Peoples._internal();

  Peoples._internal();


  factory Peoples(int id, String name) {
    _inst.id = id;
    _inst.name = name;
    return _inst;
  }
}

Hoe answered 29/3, 2022 at 9:14 Comment(0)
B
0
class BasketService {
  late String basketId;

  static final BasketService _instance = BasketService._internal();
  BasketService._internal();

  factory BasketService(String basketUniqueId) {
    _instance.basketId = basketUniqueId;
    return _instance;
  }
  factory BasketService.getInstance() {
    return _instance;
  }
}
Bossuet answered 11/1, 2023 at 15:33 Comment(0)
A
0

If you want also to pass some variables, you could do something like the following:

class Person {
  const Person._({
    required String name,
    required String lastname,
  })  : _name = name,
        _lastname = lastname;

  static Person? _instance;

  final String _name;
  final String _lastname;

  factory Person.getInstance({
    required String name,
    required String lastname,
  }) =>
      _instance ??= Person._(name: name, lastname: lastname);

  String get name => _name;
  String get lastname => _lastname;

  }
}
Andreas answered 26/7 at 16:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.