DART / CHAPTER 09

Interfaces and substitution

Advanced

Implement a contract without inheriting implementation accidentally.

By the end of this chapter

  • Use an abstract class contract
  • Distinguish implements from extends
  • Design a uniform client

The idea

Every Dart class defines an interface for its public instance members. implements promises to provide that interface, but does not inherit the class’s method bodies. extends instead establishes class inheritance and reuses compatible implementation. An abstract class can declare operations that concrete classes must supply. Choose the relationship according to whether you need a contract, implementation reuse, or both.

A client that accepts an interface can work with several unrelated implementations. The method signatures tell the compiler what calls are available, while the actual object supplies the behavior. Agree on semantic details such as units, allowed inputs, and side effects. An implementation that silently changes those rules can break callers despite satisfying the compiler.

Dart example
abstract class Cost { int cents(); }
class FixedCost implements Cost {
  @override int cents() => 250;
}
class VariableCost implements Cost {
  @override int cents() => 400;
}
void main() {
  final costs = <Cost>[FixedCost(), VariableCost()];
  print(costs.fold<int>(0, (sum, cost) => sum + cost.cents()));
}
Result
650

Both concrete classes provide the required operation. The client sums results through the Cost type without inspecting implementation names.

Try it yourself

Define a LabelSource contract and implement it with two different sources of label text.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

A class uses implements on another class with two public methods. What must it provide?