How to define interfaces in Dart?
Categories:
Mastering Interfaces in Dart: A Comprehensive Guide

Explore how Dart leverages implicit interfaces and the implements
keyword to achieve polymorphism and flexible code design, enhancing your object-oriented programming skills.
In object-oriented programming (OOP), interfaces define a contract that classes must adhere to. They specify a set of methods and properties that a class must implement, without providing the implementation details themselves. Dart, unlike some other languages, doesn't have a dedicated interface
keyword. Instead, it uses an implicit interface mechanism, where every class implicitly defines an interface. This guide will walk you through how to define and use interfaces effectively in Dart, enabling you to write more modular, testable, and maintainable code.
Understanding Dart's Implicit Interfaces
In Dart, every class implicitly defines an interface containing all its instance members (methods, getters, and setters). This means you can implement any class as an interface. When a class A
implements class B
, it must provide concrete implementations for all the instance members declared in B
. This powerful feature allows for flexible code design and promotes polymorphism without the need for a separate interface declaration syntax.
class Logger {
void log(String message) {
print('Log: $message');
}
}
class ConsoleLogger implements Logger {
@override
void log(String message) {
print('Console Log: $message');
}
}
void main() {
Logger myLogger = ConsoleLogger();
myLogger.log('This is a test message.');
}
Demonstrates a class implementing another class's implicit interface.
Defining Explicit Interface Contracts with Abstract Classes
For clearer interface definitions, especially when you want to ensure that a class cannot be instantiated directly but only implemented, you can use abstract
classes. An abstract
class can define abstract methods (methods without a body) which must be implemented by any concrete class that implements or extends it. This provides a strong contract for implementers.
abstract class Shape {
void draw(); // Abstract method
double getArea(); // Abstract getter
}
class Circle implements Shape {
double radius;
Circle(this.radius);
@override
void draw() {
print('Drawing a circle with radius $radius');
}
@override
double getArea() {
return 3.14 * radius * radius;
}
}
class Rectangle implements Shape {
double width;
double height;
Rectangle(this.width, this.height);
@override
void draw() {
print('Drawing a rectangle with width $width and height $height');
}
@override
double getArea() {
return width * height;
}
}
void main() {
List<Shape> shapes = [Circle(5), Rectangle(4, 6)];
for (var shape in shapes) {
shape.draw();
print('Area: ${shape.getArea()}');
}
}
Using an abstract class to define a clear interface contract.
classDiagram direction LR class Shape { <<abstract>> +void draw() +double getArea() } class Circle { +double radius +Circle(radius) +void draw() +double getArea() } class Rectangle { +double width +double height +Rectangle(width, height) +void draw() +double getArea() } Circle --|> Shape : implements Rectangle --|> Shape : implements
Class diagram illustrating the Shape
interface implemented by Circle
and Rectangle
.
Multiple Interfaces and Mixins
Dart allows a class to implement multiple interfaces, enabling it to adhere to several contracts simultaneously. This is a powerful way to achieve multiple inheritance of types, without the complexities of multiple inheritance of implementation. Additionally, Dart's mixin
feature can be used to reuse code across different class hierarchies, often complementing interface usage by providing default implementations for certain behaviors.
abstract class Flyable {
void fly();
}
abstract class Swimmable {
void swim();
}
class Duck implements Flyable, Swimmable {
@override
void fly() {
print('Duck is flying.');
}
@override
void swim() {
print('Duck is swimming.');
}
}
void main() {
Duck myDuck = Duck();
myDuck.fly();
myDuck.swim();
}
A class implementing multiple interfaces.
implements
creates a type contract, with
(for mixins) allows code reuse. A class can implement
an interface and with
a mixin, combining both type safety and code sharing.