Interfaces in Dart

Interfaces are named collections of method signatures.

import 'dart:math';

// Here's a basic interface for geometric shapes.
abstract class Geometry {
  double area();
  double perim();
}

// For our example we'll implement this interface on
// `Rectangle` and `Circle` classes.
class Rectangle implements Geometry {
  final double width, height;

  Rectangle(this.width, this.height);

  @override
  double area() {
    return width * height;
  }

  @override
  double perim() {
    return 2 * width + 2 * height;
  }

  @override
  String toString() {
    return 'Rectangle{width: $width, height: $height}';
  }
}

class Circle implements Geometry {
  final double radius;

  Circle(this.radius);

  @override
  double area() {
    return pi * radius * radius;
  }

  @override
  double perim() {
    return 2 * pi * radius;
  }

  @override
  String toString() {
    return 'Circle{radius: $radius}';
  }
}

// Here's a generic `measure` function taking advantage of
// the Geometry interface to work on any `Geometry` object.
void measure(Geometry g) {
  print(g);
  print(g.area());
  print(g.perim());
}

void main() {
  var r = Rectangle(3, 4);
  var c = Circle(5);

  // The `Circle` and `Rectangle` classes both
  // implement the `Geometry` interface so we can use
  // instances of these classes as arguments to `measure`.
  measure(r);
  measure(c);
}

To run the program:

$ dart run interfaces.dart
Rectangle{width: 3.0, height: 4.0}
12.0
14.0
Circle{radius: 5.0}
78.53981633974483
31.41592653589793

In Dart, we use abstract classes to define interfaces. The Geometry abstract class serves as our interface, defining the method signatures for area() and perim().

We then implement this interface in the Rectangle and Circle classes. In Dart, we use the implements keyword to indicate that a class is implementing an interface.

The measure function demonstrates polymorphism - it can work with any object that implements the Geometry interface.

In the main function, we create instances of Rectangle and Circle, and pass them to the measure function, which can handle both types because they implement the Geometry interface.

This example showcases how interfaces in Dart allow for abstraction and polymorphism, enabling more flexible and reusable code.