Skip to content

Classes & Mixins

Dart constructors are richer than most languages, and Flutter uses all of it. The essentials:

class Point {
final double x, y;
// Default constructor with `this.` shorthand — assigns fields directly.
const Point(this.x, this.y);
// Named constructor — a second way to build one.
const Point.origin() : x = 0, y = 0;
// Factory constructor — can return a cached/subtype instance, not just a fresh one.
factory Point.fromMap(Map<String, double> m) => Point(m['x']!, m['y']!);
}
const p = Point(1, 2); // const construction — canonicalized
final o = Point.origin();

Three things worth internalizing:

  • const constructors (only possible when all fields are final) let callers build canonicalized instances — the basis of const widgets.
  • Named constructors (Point.origin) give multiple clear ways to construct, instead of overloading.
  • Factory constructors don’t have to return a new instance — they can return a cached one or a subtype. factory is how many Flutter/Dart classes implement singletons or parsing.

Mixins: reuse behavior across unrelated classes

Section titled “Mixins: reuse behavior across unrelated classes”

Dart has single inheritance, but mixins let you compose behavior horizontally — add a set of methods/fields to a class without a subclass relationship. This is the Flutter pattern for State classes.

mixin Logger {
void log(String msg) => print('[log] $msg');
}
mixin Validator {
bool isValid(String s) => s.isNotEmpty;
}
// Compose several capabilities with `with`:
class Form with Logger, Validator {
void submit(String value) {
if (isValid(value)) log('submitting $value');
}
}
flowchart TB
  base["class State"] -->|with| result["your State class"]
  m1["mixin
SingleTickerProviderStateMixin"] -->|with| result
  m2["mixin
WidgetsBindingObserver"] -->|with| result
Mixins add capabilities without inheritance

When you write class _MyState extends State<MyWidget> with SingleTickerProviderStateMixin, you’re mixing in the ability to be a vsync provider for animations — pure horizontal reuse.

Extension methods add methods to types you don’t own — common for tidy helpers:

extension StringX on String {
String get capitalized => isEmpty ? this : this[0].toUpperCase() + substring(1);
}
'flutter'.capitalized; // 'Flutter'

Enhanced enums carry fields and methods, not just names — great for typed, self-describing constants:

enum Status {
active('Active', true),
archived('Archived', false);
const Status(this.label, this.isVisible);
final String label;
final bool isVisible;
}
Status.active.label; // 'Active'
What can a factory constructor do that a normal constructor cannot?
What are mixins used for in Dart/Flutter?
What is required for a class to have a const constructor?
What do extension methods let you do?