Skip to main content

Mixins

Mixins let you reuse code across multiple class hierarchies without inheritance.


Basic Mixin

// Define a mixin
mixin Serializable {
Map<String, dynamic> toJson();

String toJsonString() => jsonEncode(toJson());


String toString() => toJsonString();
}

mixin Timestamped {
DateTime createdAt = DateTime.now();
DateTime? updatedAt;

void markUpdated() => updatedAt = DateTime.now();
}

mixin Validatable {
List<String> validate(); // subclass implements this

bool get isValid => validate().isEmpty;
void throwIfInvalid() {
var errors = validate();
if (errors.isNotEmpty) throw ValidationError(errors);
}
}

// Combine mixins with 'with' keyword
class User with Serializable, Timestamped, Validatable {
String name;
String email;

User(this.name, this.email);


Map<String, dynamic> toJson() => {'name': name, 'email': email};


List<String> validate() => [
if (name.isEmpty) 'Name is required',
if (!email.contains('@')) 'Invalid email',
];
}

var user = User('Alice', 'alice@example.com');
print(user.isValid); // true
print(user.toJsonString()); // {"name":"Alice","email":"alice@example.com"}
print(user.createdAt); // current time

Mixin with on Clause

Restrict which classes can use the mixin:

class Animal {
void breathe() => print('Breathe');
}

// This mixin can ONLY be used on Animal subclasses
mixin Swimming on Animal {
void swim() {
breathe(); // can call Animal methods
print('Swimming...');
}
}

mixin Flying on Animal {
void fly() {
breathe();
print('Flying...');
}
}

class Fish extends Animal with Swimming {
// ✅ Animal subclass — can use Swimming
}

// class Car with Swimming { } // ❌ Car doesn't extend Animal

class Duck extends Animal with Swimming, Flying {
// ✅ Can have both!
}

var duck = Duck();
duck.swim(); // Breathe \n Swimming...
duck.fly(); // Breathe \n Flying...

Mixin Class (Dart 3)

// mixin class can be used as both a mixin and a standalone class
mixin class Logger {
final _logs = <String>[];

void log(String message) {
_logs.add('[${DateTime.now()}] $message');
print(message);
}

List<String> get logs => List.unmodifiable(_logs);
}

// Used as a standalone class
var logger = Logger();
logger.log('Hello!');

// Used as a mixin
class ApiService with Logger {
Future<void> fetchData() async {
log('Fetching data...');
// ...
log('Done!');
}
}

Mixins vs Other Patterns

PatternWhen to Use
MixinShare behavior across unrelated classes
Inheritance"is-a" relationship, single hierarchy
Interface (implements)Define a contract
CompositionHas-a relationship (prefer over inheritance)
ExtensionAdd methods to existing/external types