Lesson 28 min

Classes & Factory Constructors

00:00 / 00:00

Classes in Dart

Dart is a class-based, single-inheritance language. Every object is an instance of a class, and every class implicitly inherits from Object.

dart
class User { // Fields final String id; final String name; int _loginCount = 0; // Private field (underscore prefix) // Generative constructor User({required this.id, required this.name}); // Getter int get loginCount => _loginCount; // Method void login() { _loginCount++; print('$name logged in (count: $_loginCount)'); } // toString override String toString() => 'User(id: $id, name: $name)'; }

Constructor Varieties

dart
class Point { final double x; final double y; // 1. Default generative constructor const Point(this.x, this.y); // 2. Named constructor — creates additional construction paths const Point.origin() : x = 0, y = 0; Point.fromMap(Map<String, double> map) : x = map['x'] ?? 0, y = map['y'] ?? 0; // 3. Redirecting constructor Point.zero() : this(0, 0); } final origin = Point.origin(); final p = Point.fromMap({'x': 3.0, 'y': 4.0});

Factory Constructors — The Most Powerful Pattern

A factory constructor controls what gets returned. It can return a cached instance, a subtype, or construct from JSON. This is the foundation of almost every Dart model class:

dart
class Config { final String apiUrl; final bool isDev; Config._internal({required this.apiUrl, required this.isDev}); // Singleton via factory static Config? _instance; factory Config.instance() { _instance ??= Config._internal( apiUrl: 'https://api.javashark.in', isDev: false, ); return _instance!; } // Factory from JSON — used in every API model factory Config.fromJson(Map<String, dynamic> json) { return Config._internal( apiUrl: json['api_url'] as String, isDev: json['is_dev'] as bool? ?? false, ); } }

const Constructors — Zero Runtime Cost

dart
class Color { final int r, g, b; const Color(this.r, this.g, this.b); // const constructor static const red = Color(255, 0, 0); static const green = Color(0, 255, 0); } // const objects are compile-time constants — allocated ONCE const myColor = Color(100, 150, 200); // Both references point to the SAME object in memory: print(identical(Color.red, Color.red)); // true

Immutable Data Classes with copyWith

dart
class Product { final String id; final String name; final double price; const Product({ required this.id, required this.name, required this.price, }); // Factory from JSON factory Product.fromJson(Map<String, dynamic> json) => Product( id: json['id'] as String, name: json['name'] as String, price: (json['price'] as num).toDouble(), ); // copyWith pattern — create modified copies Product copyWith({String? id, String? name, double? price}) => Product( id: id ?? this.id, name: name ?? this.name, price: price ?? this.price, ); Map<String, dynamic> toJson() => {'id': id, 'name': name, 'price': price}; bool operator ==(Object other) => other is Product && other.id == id; int get hashCode => id.hashCode; }

Summary

Factory constructors are one of Dart's most powerful features. They enable the singleton pattern, JSON deserialization, caching, and polymorphic construction — all through a clean, unified constructor syntax. Pair them with const constructors and copyWith for an ergonomic, immutable data layer.

WhatsApp