Interfaces and implements
Prerequisites: Inheritance
Dart has no separate interface keyword for defining one: every class
is also an interface. implements promises to provide all of a
class's members — without inheriting any code.
Real-world analogy: an interface is a job description ("must be able to drive, must have a license"). Anyone who meets it can do the job.
Example
abstract class Notifier {
String get channel;
String send(String message);
}
class EmailNotifier implements Notifier {
final String address;
EmailNotifier(this.address);
@override
String get channel => 'email';
@override
String send(String message) => 'Email to $address: $message';
}
class SmsNotifier implements Notifier {
@override
String get channel => 'sms';
@override
String send(String message) =>
'SMS: ${message.length > 20 ? message.substring(0, 20) : message}';
}
void main() {
final List<Notifier> notifiers = [EmailNotifier('ada@example.com'), SmsNotifier()];
for (final n in notifiers) {
print('[${n.channel}] ${n.send('Your order has shipped today')}');
}
}
Expected output
[email] Email to ada@example.com: Your order has shipped today
[sms] SMS: Your order has shipp
- An abstract class with no implementation is the usual way to define an interface.
- A class can implement several interfaces:
class Robot implements Walker, Talker. - Code that uses a
Notifierdoesn't care which kind it has, so adding a new channel needs no change to that code.
extends vs implements
extends— inherit the superclass's code; only one superclass.implements— promise the same members, but write them all yourself; as many as you like.
Interfaces make code testable
Depending on an interface lets tests pass a fake implementation — for
example, a FakeNotifier that records messages instead of sending them.
You'll use this in the Testing lesson.
Common mistakes
- Implementing an interface and forgetting a member:
The non-abstract class 'SmsNotifier' is missing implementations for these members. Your editor's quick fix can add stubs.