100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Constructors and Factory Constructors

Master Dart's constructor forms, default, named, const, and factory constructors, and learn when each pattern is the right tool for building objects.

Collections & OOPIntermediate10 min readJul 10, 2026
Analogies

Constructors and Factory Constructors

A constructor is the special function that runs when an object is created, guaranteeing every instance starts in a valid state. Dart offers a rich set of constructor forms, the default generative constructor, named constructors, const constructors, and factory constructors, each suited to a different creation scenario.

🏏

Cricket analogy: When a new player object is registered mid-season, a constructor is like the registration form: it ensures every Batsman object starts with a name and zero runs set at creation, not left undefined.

Named and Initializer-List Constructors

Named constructors, written as ClassName.name(...), let a single class offer multiple distinct ways to build an instance. An initializer list, the part after the colon and before the constructor body, runs before the body and can assign final fields or delegate to the superclass via super(...).

🏏

Cricket analogy: Defining Batsman.debutant(String name) as a named constructor with runs and matches both set to zero lets you create a fresh rookie object distinctly from Batsman.withStats(name, runs, matches) for an experienced player, both building the same class differently.

dart
class Batsman {
  final String name;
  final int runs;
  final int matches;

  Batsman(this.name, this.runs, this.matches);

  // Named constructor with an initializer list
  Batsman.debutant(String name)
      : name = name,
        runs = 0,
        matches = 0;

  Batsman.withStats(this.name, this.runs, this.matches);
}

void main() {
  var rookie = Batsman.debutant('Yashasvi Jaiswal');
  var veteran = Batsman.withStats('Rohit Sharma', 4200, 250);
  print('${rookie.name}: ${rookie.runs} runs');
}

Factory Constructors

A factory constructor, declared with the factory keyword, is not required to return a brand-new instance of its own class the way a generative constructor is. It can return a cached object, choose and return a subtype based on input, or run arbitrary setup logic before deciding what to hand back.

🏏

Cricket analogy: A factory constructor like factory Batsman.fromRole(String role) can inspect the role string and return either an Opener or a Finisher subclass instance, deciding at runtime which concrete object to hand back instead of always building a plain Batsman.

A factory constructor uses the factory keyword and, unlike a generative constructor, is not required to create a new instance of its own class. It can return a cached instance, a subtype, or run arbitrary logic before returning an object.

const Constructors

A const constructor produces compile-time constant instances: every field must be final, and Dart canonicalizes const objects, meaning two const invocations with identical arguments literally return the same object in memory, which identical() can confirm and which saves memory for frequently repeated immutable values.

🏏

Cricket analogy: A const constructor on an immutable PitchCondition class ensures const PitchCondition('Dry', 'Spin-friendly') created in two different places in code resolves to the exact same canonical object in memory, since Dart canonicalizes identical const instances.

dart
class Logger {
  final String name;
  static final Map<String, Logger> _cache = {};

  Logger._internal(this.name); // private named constructor

  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }
}

class Currency {
  final String code;
  const Currency(this.code); // const constructor
}

void main() {
  var log1 = Logger('network');
  var log2 = Logger('network');
  print(identical(log1, log2)); // true, same cached instance

  const usd1 = Currency('USD');
  const usd2 = Currency('USD');
  print(identical(usd1, usd2)); // true, canonicalized const instance
}

For a class to have a const constructor, every field must be final, and any field values passed in must themselves be compile-time constants. Forgetting final on a field is the most common reason a const Constructor(...) fails to compile.

  • A constructor initializes an object's fields at the moment it is created, guaranteeing valid starting state.
  • Named constructors (ClassName.name(...)) let a class offer multiple ways to build an instance, each with different defaults.
  • Initializer lists (: field = value) run before the constructor body and can only assign to final fields, not call arbitrary methods.
  • A factory constructor, marked with the factory keyword, is not required to return a new instance; it can return a cached or subtype instance.
  • Factory constructors are ideal for implementing caching, singletons, and 'return a subclass based on input' patterns.
  • const constructors require all fields to be final and produce canonicalized, compile-time-constant instances when called with const.
  • identical(a, b) returns true for two const instances built with the same constant arguments, since Dart reuses the same object.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#DartStudyNotes#ConstructorsAndFactoryConstructors#Constructors#Factory#Named#Initializer#StudyNotes#SkillVeris#ExamPrep