I have created a class as singleton making a static method to get the instance of that class but while unit test I am not able to mock that class. Is there any other way in dart to only create a single instance and that can be easily unit tested.
There are different ways depending on what your exact requirements are.
You could use an additional class to access the singleton where you can create multiple instances while still being guaranteed that the value it allows to access will be a singleton:
class MySingleton {
static final MySingleton value = MySingleton.();
MySingleton._();
}
class MySingletonHelper {
MySingleton get value => MySingleton.value;
}
or and alternative way using #visibleForTesting with the limitation that the singleton value can not be final and write access is only limited by the DartAnalyzer, but not by the compiler (I wouldn't consider this a serious limitation):
import 'package:meta/meta.dart';
class MySingleton {
static MySingleton _value = MySingleton.();
static MySingleton value => get _value;
#visibleForTesting
static set value(MySingleton val) => _value = val;
MySingleton._();
}
Related
I want to set up a mixin with standard persistence behavior. The mixin looks like that:
mixin Persistence<T> {
static late final PersistenceBase persistence;
static void add(T object) {
persistence.add(object);
}
static void delete(T object) {
persistence.delete(object);
}
static T elementAt(int index) => persistence.elementAt(index);
static Iterable<T> getAll() => persistence.getAll();
static T get first => persistence.getFirst();
static T get last => persistence.getLast();
static int get length => persistence.getLength();
}
Usage of persistence would look like that:
class A with Persistence {
String var1;
int var2;
}
A.add(A("test", 1));
var length = A.getLength();
A firstElement = A.getFirst();
However Dart doesn't allow using generics with static methods:
Static members can't reference type parameters of the class.
Try removing the reference to the type parameter, or making the member an instance member
The point is that I don't want to create instance of A class just to access persistence functionality for the class.
So far I have done this way:
class PersistenceManager<T> {
late final PersistenceBase persistence;
void add(T object) {
persistence.add(object);
}
void delete(T object) {
persistence.delete(object);
}
T elementAt(int index) => persistence.elementAt(index);
Iterable<T> getAll() => persistence.getAll();
T get first => persistence.getFirst();
T get last => persistence.getLast();
int get length => persistence.getLength();
}
class Asset {
static final persistenceMgr = PersistenceManager<Asset>();
...
}
Asset.persistenceMgr.add(Asset());
That though requires adding mandatory static field for each class that would use persistence.
Is there other more elegant solution?
This is not going to work.
Dart mixin application works by mixing in the instance members of the mixin, and doing nothing to the static members.
You won't be able to do A.elementAt(...) with or without generics, because the A class doesn't have any static elementAt method. The Persistance mixin has one, but you have to call it as Persistance.elementAt. It's not the same namespace as A, and there is no inheritance, or mixin-in, of static members.
If you want a PersistanceBase per class, you do need to declare it yourself, and putting the methods which operate on the base onto the same per-class value seems like the optimal design.
So, no, there is no other more elegant solution. What you have is elegant.
In dart when creating a mixin, you can declare properties and methods like a class. When declaring a private property/method, it seems the inheriting class should also have access to this private member (see below for example).
Is there a way to access a mixin's private variable in the class using the mixin?
If it's not possible, how can I declare a member in the mixin object but make it private in the inheriting class's interface.
mixin.dart
mixin A {
String propertyOne = '1';
// This property is not accessible to any inheriting class.
int _privateProperty = 2;
}
class.dart
class B with A {
String get mixinString => propertyOne;
// This property is not accessible to the B class.
int get mixinInt => _privateProperty;
}
No. A property being library private means that you can only express its name inside the same library. In any other library, the identifier _privateProperty is a different name, one private to that other library.
If you cannot declare both mixin and class in the same library, and you definitely need access to the property, then you can do any number of things to allow that.
Make the property public and tell people not to use it except in subclasses. They still can if they want to.
Make the property public and mark it #protected, to have the analyzer tell people to not use it except in subclasses. They still can if they want to.
Keep the property private and provide a separate method to access it:
mixin A {
// This property is not accessible to any inheriting class.
int _privateProperty = 2;
static int getPrivateProperty(A a) => a._privateProperty;
static void setPrivateProperty(A a, int value) {
a._privateProperty = value;
}
}
Anyone can still get to the property if they really want to, but they need to know that
it comes from A.
I'm working on a library, and I have a implementation pattern users are required to follow:
class MyView extends LibView {
static Foo f = Foo();
#override
void render(){
use(f); // f should be static, otherwise things not work correctly
}
}
I would like to tell the compiler that, if someone ever does this, it's incorrect:
class MyView {
Foo f = Foo(); // Error: Foo can only be used in Static field.
...
}
Anyone know if this is possible? I find it really hard to find good docs on these sorta of language details when it comes to dart.
[EDIT] Since the "why" question always comes up, imagine something like:
class ViewState{
Map<int, Object> props = {};
}
ViewState _state = ViewState();
class View {
View(this.state);
ViewState state;
static int _key1 = getRandomInt();
void render(){
print(state(_key1))
}
}
// These should both print the same value off of state since the 'random' int is cached
View(_state);
View(_state);
If the key's were not static, everything would compile fine, but they would not print the same results.
What you properly need are a singleton which can be created in different ways in Dart. One way is to use a factory constructor like this:
class Foo {
static final Foo _instance = Foo._();
factory Foo() => _instance;
// Private constructor only used internally
Foo._();
}
void main() {
final a = Foo();
final b = Foo();
print(identical(a, b)); // true
}
By doing it like this, there will only be one instance of Foo which are then shared each time an instance are asked for. The instance are also first created the first time it is asked for since static variables in Dart are lazy and only initialized when needed.
I just want to do the functional equivalent of
int someUniqueKey = 0, or MyViewEnums.someUniqueKey but do it with a typed object rather than a int/enym, like: Object<Foo> someUniqueKey = Object<Foo>(). In order for this to work with Objects, it needs to be static. It's similar to how int someUniqueKey = random.nextInt(9999) would have to be static in order to be used as a key that all instances could share. That way keys are auto-managed and unique, and people don't need to assign int's, strings, or whatever. It also has the advantage of letting me use the type later for compile time checks.
bool prop = getPropFromRef(_prop1Ref); //Will throw error prop1Ref is not Ref<bool>
I think I've figured out something that does the trick using darts package-level methods.
class Ref<T> {}
// Re-use existing ref if it already exists
Ref<T> getRef<T>(Ref<T> o) => o ?? Ref<T>();
class RefView {}
// In some other package/file:
class MyView extends RefView {
static Ref<bool> prop1Ref = getRef(prop1Ref);
static Ref<int> prop2Ref = getRef(prop2Ref);
}
This will make sure that prop1 and prop2 have the same values across all instances of MyView and it will throw an error if these are not static (since you can not pass an instance field before Constructor)
This still has the downside of a potential hard to spot error:
class MyView extends RefView {
static Ref<bool> prop1 = getRef(prop1);
static Ref<bool> prop2 = getRef(prop1); // passing prop1 to prop2's getRef, and they have the same<T>, compiler will miss it
}
But I think it might be preferable than having this potential error:
class MyView extends RefView {
//Both of these will fail silently, keys will change for each instance of MyView
Ref<bool> prop1 = getRef(prop1);
Ref<bool> prop2 = getRef(prop2);
}
I am new to Dart and Flutter. While I am going through tutorials, I got that we can make singleton using factory keyword. But after that, I got this code.
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal();
static AccountService getInstance() {
return _instance;
}
}
My questions.
How does the code work?
when getInstance() get called?
is AccountService._internal() a constructor?
static final _instance = AccountService._internal(); - When this get called?
Please help me
Static fields in Dart are all lazy evaluated so they will first get its value the first time you access the field.
So:
When you call getInstance(), it will return the value of the field _instance. If this is the first time the field will be evaluated so AccountService._internal() is called. If it is second time, the value from previous access is reused.
First time you call the method somewhere in your code? If you are never calling the method, the object referenced by _instance will never be created.
Yes, it is a named constructor and because the name starts with "_" it is only available from the library this class is part of. By doing so, it is possible to restrict new objects from this class so only the class itself are allowed to create an instance.
It is called first time _instance is accessed. Since this name also starts with "_" it is only available from the library this class is part of.
The lazy initialization of static fields is described in the Dart specification with the following reasoning:
Static variable declarations with an initializing expression are initializedlazily (8.1).
The lazy semantics are given because we do not want a language where one tends to define expensive initialization computations, causing long application startup times. This is especially crucial for Dart, which must support the coding of client applications.
https://dart.dev/guides/language/specifications/DartLangSpec-v2.2.pdf
Added code example
class AccountService {
static final _instance = AccountService._internal();
AccountService._internal() {
print(':: Calling AccountService._internal constructor');
}
static AccountService getInstance() {
print(':: Calling getInstance()');
return _instance;
}
}
void main() {
print(':: Step 1');
AccountService.getInstance();
print(':: Step 2');
AccountService.getInstance();
print(':: End');
}
Output:
:: Start
:: Step 1
:: Calling getInstance()
:: Calling AccountService._internal constructor
:: Step 2
:: Calling getInstance()
:: End
Since there is no official library from the flutter team, I'm trying to implement the dependency injection in flutter manually using the singleton pattern, after a long search this is what I came up with:
class Injector{
Injector._internal();
static final _singleton = new Injector._internal();
factory Injector() => _singleton;
SomeClass get someClass => new SomeClass();
}
Now, Injector is singleton that has one instance once instantiated and SomeClass is the dependency I want to inject in my code. The above code works, but the problem is where should I instantiate the Injector class and make it available every where in my code. Do you think Global Variable is good in this situation or is there a better way? Thanks.
To implement your own dependency injection I usually use a combination of
A 'Bindings' class which has getters to all injected services
A static getter/setter which holds a single instances of the Bindings class. This is important for overriding the bindings.
The getters which return classes should lazily construct them if they have dependencies. This allows you to override any parts of your graph by extending the Bindings class and setting it in the global bindings. For example, below I have three classes with the third depending on the first two.
class Foo {}
class Bar {}
class Fizz {
Fizz(this.foo, this.bar);
final Foo foo;
final Bar bar;
}
class Bindings {
/// Can be final since there are no dependencies
final Foo foo = new Foo();
final Bar bar = new Bar();
Fizz _fizz;
Fizz get fizz {
_fizz ??= new Fizz(foo, bar);
return _fizz;
}
}
Bindings get bindings => _bindings;
Bindings _bindings;
set bindings(Bindings value) {
_bindings = value;
}
Now suppose I want to override Foo for testing. I can extend the Bindings class and override the field/getter that returns Foo. and in my test setup, I set bindings with this new instance. Now when Fizz is created, the MockFoo instance is used instead of Foo
class MockFoo implements Foo {}
class BindingsOverride extends Bindings {
#override
final Foo foo = new MockFoo();
}
void main() {
bindings = new BindingsOverride();
}
Edit: In an earlier version I was using a static class. I don't think you need to refer to foo and bar through the bindings instance, you can just refer to the members directly.
This is my solution for this problem. First I created a dart file named injector.dart with this code:
// the singleton is private to this package
final _injector = new _Injector();
// expose depedencies
final foo = _injector.foo;
final bar = _injector.bar;
class _Injector{
// create a singleton
_Injector._internal();
static final _singleton = new _Injector._internal();
factory _Injector() {
return _singleton;
}
// the dependecies
Foo get foo => new Foo();
Bar get bar => new Bar();
}
This is how the code work, first we create a singleton class _Injector that creates needed dependencies and then exposes these dependencies with top-level variables. This way the dependencies are accessible anywhere the injector.dart package is accessible.
What do you think guys? is this good or is there a better implementation? Thanks