rahul  Kushwaha
rahul Kushwaha

Reputation: 2819

How to restrict the creation of instance of class to one in dart?

I have a class Data:

class Data {
  int a;
  int b;
  Data({this.a, this.b})
}

I want to create just one object of this class for the entire app.

And all the other classes should be able to instantiate the Data class but internally it should return same object which should be constant.

Is there any way to apply the above restriction to class in Dart?

Upvotes: 2

Views: 948

Answers (1)

Abion47
Abion47

Reputation: 24661

There are a couple ways to achieve this. One is with regular old constants:

class Data {
  final int a;
  final int b;

  const Data({this.a, this.b});
}

This may look like it doesn't apply the constraits you are looking for, but actually there is a subtle feature of Dart constants called canonical instances. This means that every const value declared in a program with the same values for fields gets turned into a single known value at compile time. This value is then referenced everywhere the constant gets "instantiated" in code:

const a = Data(a: 1, b: 3);
const b = Data(a: 1, b: 3);
const c = Data(a: 2, b: 4);
// Both `a` and `b` here point to the same object in memory.
// `c` is a different object because the values passed as parameters are different.

Another way is with a singleton. This basically takes a normal instance and treats it like a static value for the entire class. The simplest way to do it in Dart would be with a non-named factory constructor:

class Data {
  int a;
  int b;

  Data _instance;
  Data._({this.a, this.b});
  factory Data({int a, int b}) {
    _instance ??= new Data._(a: a, b: b);
    return _instance;
  }
}

The above code creates what is known as a lazily instantiated singleton, which basically means the instance doesn't get created until it is actually needed. Using a factory method means that you get to specify which instance actually gets returned, which here means we can just return _instance every time. This means that all code that creates a new Data instance is just returned the same value of _instance:

Foo a = Data(a: 1, b: 3);
Foo b = Data(a: 1, b: 3);
Foo c = Data(a: 2, b: 4);
// a, b, and c are all the same instance of Foo

(One thing to be wary of in this approach, though, is that _instance is only created on the first time the factory constructor is called, and that's when the values for a and b are taken. This means that from that point on, every time the constructor is called, the parameters for a and b are ignored, such as in the above example where different values are passed for a and b. This is why singletons aren't a good choice for service classes that take parameters.)

There are more advisable ways of doing this, though. One is to use a service locator like the get_it package to create a normal instance and then expose it to the entire package in a decoupled way:

import 'package:get_it/get_it.dart';

void createSingleton() {
  GetIt.instance.registerSingleton(Data(a: 1, b: 3));
}

Now you can retrieve that same value calling get:

final data = GetIt.instance.get<Data>();

This might seem like it's more work, but it makes your code more flexible by not tying your code to a particular type or implementation. This comes in handy when implementing things like dependency injection and unit testing.

Upvotes: 4

Related Questions