I'm trying to figure out if my updated code is the correct way to use a factory constructor with null safety. I reviewed stackoverflow and the Dart.dev language tour to try to better understand factory constructors. I have struggled to apply the concepts outlined to my code. I'm new to Flutter, Dart and coding. This is my first attempt at using a factory constructor so the primary issue is my lack of understanding and not any issues with the answers on stackoverflow or elsewhere.
After reading a lot I settled on the approach in the code below marked as Updated. The errors are now all gone and my app is behaving as I want but my fear is throwing an error instead of returning null may not be a sound approach. My approach just looks wrong to my beginner eyes. My goal is for my code to work and to also understand why I am using whatever approach I am using so that I can apply that knowledge to future situations. I can provide any additional code that may be needed to comment. Thanks in advance for the help.
Original Code that throws an error
class Job {
Job({required this.name, required this.ratePerHour});
factory Job.fromMap(Map<String, dynamic>? data) {
if (data == null) {
return null;
}
final String name = data['name'];
final int ratePerHour = data['ratePerHour'];
return Job(name: name, ratePerHour: ratePerHour);
}
final String name;
final int ratePerHour;
Map<String, dynamic> toMap() {
return {
'name': name,
'ratePerHour': ratePerHour,
};
}
}
Updated code that works
class Job {
Job({required this.name, required this.ratePerHour});
factory Job.fromMap(Map<String, dynamic>? data) {
if (data != null) {
final String name = data['name'];
final int ratePerHour = data['ratePerHour'];
return Job(name: name, ratePerHour: ratePerHour);
} else {
throw ArgumentError('Data is null');
}
}
final String name;
final int ratePerHour;
Map<String, dynamic> toMap() {
return {
'name': name,
'ratePerHour': ratePerHour,
};
}
}
CodePudding user response:
Your own solution works fine however, I would check data before calling the factory.
factory Job.fromMap(Map<String, dynamic> data) {
return Job(name: data['name'], ratePerHour: data['ratePerHour']);
}
But then again why not use data and call the regular constructor?
Job? job;
if (data != null) {
job = Job(name: data['name'], ratePerHour: data['ratePerHour'])
}
https://dart.dev/guides/language/language-tour#factory-constructors
Factory constructors
Use the factory keyword when implementing a constructor that doesn’t always create a new instance of its class. For example, a factory constructor might return an instance from a cache, or it might return an instance of a subtype. Another use case for factory constructors is initializing a final variable using logic that can’t be handled in the initializer list.
CodePudding user response:
You've pointed out several true and good facts, and I feel like that you're on the right way to implement this.
I also feel like there's no straight "right" answer to this question; I think this also connects to concepts as clean code and clean architecture, which are broader than Dart and Flutter themselves
You can either:
- Throw and let the caller (upper layer) handle that problem;
- Print some logs and return a zero-value to the caller (in your case, an "empty" object).
Case 1 is desirable if you don't want to handle cases like that one.
Case 2 is desirable if you can afford to return something weird like a Job("job name",0)
and still be good.
It really depends on what you're building. By looking at your context, I'd probably go with option 1 and try/catch that in a middle layer (maybe you want to show your user "An error occured" whenever data
is null
)?