Constructors & Named Parameters
Multiple Ways to Build Your Objects
Open interactive version (quiz + challenge)Real-world analogy
What is it?
Constructors are special methods that create and initialize objects. Dart gives you many flavors: default constructors for the common case, named parameters for clarity, named constructors for alternative creation paths, factory constructors for advanced logic, and const constructors for compile-time optimization. Understanding constructors is essential because Flutter widgets are constructed thousands of times during rebuilds.
Real-world relevance
In team_mvp_kit, constructors are everywhere. Widget classes use const constructors with named parameters for readability: const HomeScreen(key: key). Model classes use factory UserModel.fromJson(json) to parse API responses from Dio. Entity classes use const constructors so identical entities can be reused in memory. BLoC classes use default constructors with dependency injection via GetIt.
Key points
- Default Constructor — The simplest constructor shares the class name. Dart's shorthand this.property automatically assigns parameters to properties, saving you from writing boilerplate assignment code.
- Named Parameters — Wrap parameters in curly braces to make them named. Named parameters are optional by default, so use required to enforce them. They make code readable -- you always know which value goes where.
- Default Values — Named parameters can have default values. If the caller does not provide a value, the default kicks in. This is great for configuration objects with sensible defaults.
- Named Constructors — Dart allows multiple constructors using ClassName.name syntax. Each named constructor can initialize the object differently. Common patterns include .empty(), .fromMap(), and .guest().
- Factory Constructors — A factory constructor can return an existing instance, a subtype, or compute the object before returning it. Unlike normal constructors, factory constructors have a body that must explicitly return an instance.
- Const Constructors — If all fields are final and known at compile time, mark the constructor as const. This lets Dart reuse identical objects instead of creating duplicates, saving memory.
- Initializer Lists — Code that runs before the constructor body, used to set final fields, assert preconditions, or call the super constructor. Initializer list entries are separated by commas after a colon.
- Redirecting Constructors — A constructor can delegate to another constructor in the same class using a colon and this(). This avoids duplicating initialization logic across multiple constructors.
- fromJson Factory Pattern — In team_mvp_kit, model classes use factory constructors named fromJson to parse API responses. This pattern converts raw Map data into typed Dart objects safely.
- toJson Method Pattern — Paired with fromJson, toJson converts an object back to a Map for sending to APIs or storing locally. Together they form the serialization/deserialization pattern used throughout team_mvp_kit.
Code example
class UserModel {
final String id;
final String name;
final String email;
final DateTime createdAt;
const UserModel({
required this.id,
required this.name,
required this.email,
required this.createdAt,
});
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
id: json['id'] as String,
name: json['name'] as String,
email: json['email'] as String,
createdAt: DateTime.parse(json['created_at'] as String),
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
'created_at': createdAt.toIso8601String(),
};
}
UserModel copyWith({String? name, String? email}) {
return UserModel(
id: id,
name: name ?? this.name,
email: email ?? this.email,
createdAt: createdAt,
);
}
}Line-by-line walkthrough
- 1. Define UserModel class -- this represents user data from the API
- 2. Declare final String id -- immutable unique identifier
- 3. Declare final String name -- immutable user name
- 4. Declare final String email -- immutable email address
- 5. Declare final DateTime createdAt -- immutable timestamp of account creation
- 6. Define a const constructor with required named parameters using this.field shorthand
- 7. The factory UserModel.fromJson constructor takes a Map parameter
- 8. It returns a new UserModel by extracting and casting each value from the JSON map
- 9. Parse the id field from json as a String
- 10. Parse the name field from json as a String
- 11. Parse the email field from json as a String
- 12. Parse created_at from json as a String and convert it to DateTime using DateTime.parse
- 13. The toJson method returns a Map for serialization
- 14. Include id, name, email as string values in the map
- 15. Convert createdAt to ISO 8601 string format for JSON compatibility
- 16. The copyWith method takes optional parameters for each field you might want to change
- 17. It returns a new UserModel with provided values or falls back to existing values using the ?? operator
- 18. For fields not in copyWith parameters like id and createdAt, the original values are always reused
Spot the bug
class Temperature {
final double celsius;
const Temperature(this.celsius);
factory Temperature.fromFahrenheit(double f) {
final c = (f - 32) * 5 / 9;
Temperature(c);
}
}Need a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- Dart Constructors (dart.dev)
- Named Parameters in Dart (dart.dev)
- Factory Constructors Explained (dart.dev)