YouTip LogoYouTip

Dart Interfaces And Mixins

Dart Interfaces and Mixins | Beginner's Tutorial

Although Dart only supports single inheritance, multiple code reuse can be flexibly achieved through interfaces and mixins.

This chapter introduces how to use implements to implement interfaces, code reuse with mixin, and the with keyword.


implements for Interfaces

In Dart, every class implicitly defines an interface.

Using the implements keyword allows a class to implement another class's interface, and multiple interfaces can be implemented.

Example

// Define a "printable" interface

class Printable {

  // Methods in the interface have no default implementation

  // Implementers must override all members

  void printContent(){

    // This method body is ignored when using implements

  }

}

// Define a "savable" interface

class Savable {

  void save(){}

}

// Use implements to implement multiple interfaces

class Document implements Printable, Savable {

  String title;

  String content;

  Document(this.title, this.content);

  // Must implement all methods required by the Printable interface

  @override

  void printContent(){

    print('--- Document: $title ---');

    print(content);

    print('--- TUTORIAL print end ---');

  }

  // Must implement all methods required by the Savable interface

  @override

  void save(){

    print('Document "$title" has been saved to disk');

  }

}

void main(){

  var doc = Document('Dart Tutorial', 'This is a Dart beginner guide');

  // Polymorphism: Document is both Printable and Savable

  Printable printable = doc;

  printable.printContent();

  Savable savable = doc;

  savable.save();

}
--- Document: Dart Tutorial ---
This is a Dart beginner guide
--- TUTORIAL print end ---
Document "Dart Tutorial" has been saved to disk

The key difference between implements and extends: extends inherits all implementations (method bodies) from the parent class, while implements only inherits the interface signaturesβ€”you must re-implement all methods. Additionally, extends can only inherit from one class, while implements can implement multiple interfaces.

extends vs implements Comparison

Feature extends implements
Quantity Limit Can only inherit one Can implement multiple
Method Implementation Inherits parent's implementation Must implement all methods yourself
Constructor Can call super() Does not inherit constructors
Use Case "Is a" relationship "Can do" contract

Multiple Interface Implementation

Dart can implement multiple interfaces, which is the main way to break through the single inheritance limitation.

Example

// Define multiple behavior interfaces

class Flyable {

  void fly(){}

}

class Swimmable {

  void swim(){}

}

class Walkable {

  void walk(){}

}

// A duck can fly, swim, and walk

class Duck implements Flyable, Swimmable, Walkable {

  String name;

  Duck(this.name);

  @override

  void fly(){

    print('$name is flying in the sky');

  }

  @override

  void swim(){

    print('$name is swimming on the water');

  }

  @override

  void walk(){

    print('$name is waddling on land');

  }

}

// A fish can only swim

class Fish implements Swimmable {

  @override

  void swim(){

    print('The fish is swimming in the water');

  }

}

void main(){

  var duck = Duck('TUTORIAL Duck');

  // Duck can play multiple roles

  (duck as Flyable).fly();

  (duck as Swimmable).swim();

  (duck as Walkable).walk();

  // Type check

  print('Can the duck fly? ${duck is Flyable}');

  print('Can the duck swim? ${duck is Swimmable}');

  var fish = Fish();

  print('Can the fish fly? ${fish is Flyable}');

}
TUTORIAL Duck is flying in the sky
TUTORIAL Duck is swimming on the water
TUTORIAL Duck is waddling on land
Can the duck fly? true
Can the duck swim? true
Can the fish fly? false

Mixin Code Reuse

Mixin is a mechanism for reusing code across multiple classes. It solves the problem where "multiple classes need to share the same methods but inheritance is not suitable."

Use the mixin keyword to define a Mixin, and use the with keyword to mix it into a class.

Example

// Use mixin keyword to define

mixin Logger {

  // Methods in Mixin can be reused by multiple classes

  void log(String message){

    print('[${DateTime.now()}] $message');

  }

  void logError(String message){

    print('[ERROR ${DateTime.now()}] $message');

  }

}

mixin TimestampFormatter {

  String formatTimestamp(DateTime dt){

    return '${dt.year}-${dt.month.toString().padLeft(2, '0')}'

        '-${dt.day.toString().padLeft(2, '0')}';

  }

}

// Use with keyword to mix in Mixin

class UserService with Logger, TimestampFormatter {

  void createUser(String name){

    log('Creating user: $name');

    var now = DateTime.now();

    print('Creation time: ${formatTimestamp(now)}');

  }

}

class OrderService with Logger {

  void createOrder(String orderId){

    log('Creating order: $orderId');

  }

  void cancelOrder(String orderId){

    logError('Failed to cancel order: $orderId');

  }

}

void main(){

  var userService = UserService();

  userService.createUser('tutorial');

  var orderService = OrderService();

  orderService.createOrder('ORD-001');

  orderService.cancelOrder('ORD-001');

}
[2026-06-12 10:30:00.000] Creating user: tutorial
Creation time: 2026-06-12
[2026-06-12 10:30:00.001] Creating order: ORD-001
[ERROR 2026-06-12 10:30:00.001] Failed to cancel order: ORD-001

UserService and OrderService come from different business domains and are not suitable for sharing Logger through inheritance.

Through Mixin, they can both obtain logging functionality without affecting each other.

Mixin cannot have constructors, nor can it be instantiated. Its purpose is pure: to provide reusable methods without involving state initialization.

Mixin Restriction Conditions

Mixin can use the on keyword to restrict that it can only be used with specific types of classes.

Example

// Base class

class Animal {

  String name;

  Animal(this.name);

}

// This Mixin can only be mixed into Animal and its subclasses

mixin FlyableMixin on Animal {

  void fly(){

    print('$name took flight!');

  }

}

// Bird is an Animal, so it can use FlyableMixin

class Bird extends Animal with FlyableMixin {

  Bird(String name): super(name);

}

// The following line will cause an error: Car is not an Animal, cannot use FlyableMixin

// class Car with FlyableMixin {} // Error!

void main(){

  var bird = Bird('TUTORIAL Little Bird');

  bird.fly();

  // Methods in FlyableMixin can access Animal's property name

  print('Bird name: ${bird.name}');

}
TUTORIAL Little Bird took flight!
Bird name: TUTORIAL Little Bird

Complete Combination of class, Mixin, extends, and implements

In Dart, a class can simultaneously use extends, with, and implements:

Example

mixin Jumpable {

  void jump() => print('Jumped!');

}

mixin Runnable {

  void run() => print('Running forward!');

}

class Animal {

  void breathe() => print('Breathing...');

}

// Inherit Animal, mix in Jumpable and Runnable, implement Comparable

class Athlete extends Animal

    with Jumpable, Runnable

    implements Comparable<Athlete> {

  String name;

  int score;

  Athlete(this.name, this.score);

  @override

  int compareTo(Athlete other) => score.compareTo(other.score);

  void showSkills(){

    breathe();

    run();

    jump();

  }

}

void main(){

  var a1 = Athlete('TUTORIAL Player A', 95);

  var a2 = Athlete('Player B', 88);

  a1.showSkills();

  print('${a1.name} vs ${a2.name}: ${a1.compareTo(a2) > 0 ? "A wins" : "B wins"}');

}
Breathing...
Running forward!
Jumped!
TUTORIAL Player A vs Player B: A wins

Complete declaration order: class Subclass extends Parent with Mixin1, Mixin2 implements Interface1, Interface2

← Dart Exception HandlingDart Classes And Objects β†’