100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Abstract Classes and Interfaces

Understand how Dart uses abstract classes to define partial blueprints and implicit interfaces via implements to enforce contracts without sharing code.

Collections & OOPIntermediate10 min readJul 10, 2026
Analogies

Abstract Classes and Interfaces

An abstract class, declared with the abstract keyword, defines a partial blueprint that cannot be instantiated directly. It typically declares one or more abstract methods, signatures with no body, that every concrete subclass must implement, letting the abstract class enforce a contract while optionally sharing real code too.

🏏

Cricket analogy: An abstract class like Bowler declaring an unimplemented bowl() method is like the ICC rulebook defining that every bowler must have a delivery action without specifying whose style it is; you can never field an actual player who is just a generic 'Bowler', only a concrete SpinBowler or PaceBowler.

Defining Abstract Classes

An abstract class can freely mix abstract methods, no body at all, with fully concrete methods that already have working implementations. This lets shared logic live once on the abstract class while forcing each subclass to fill in only the truly type-specific behavior via its own abstract method implementation.

🏏

Cricket analogy: abstract class Bowler with fields and an abstract bowl() method alongside a concrete announce() method mixes an unimplemented bowl() method with a fully concrete announce() method, and Dart refuses new Bowler('X') because it contains an abstract member.

dart
abstract class Bowler {
  String name;
  Bowler(this.name);

  void bowl(); // abstract method, no body

  void announce() => print('$name is coming in to bowl'); // concrete method
}

class SpinBowler extends Bowler {
  SpinBowler(String name) : super(name);

  @override
  void bowl() => print('$name delivers a leg-break');
}

void main() {
  // Bowler('X'); // Error: abstract classes can't be instantiated
  var bowler = SpinBowler('Ravichandran Ashwin');
  bowler.announce();
  bowler.bowl();
}

Implicit Interfaces with implements

Every Dart class implicitly defines an interface made up of its members, and any class, abstract or not, can be used purely as a contract through the implements keyword. Unlike extends, implements never carries over implementation code, so the implementing class must write its own version of every single member.

🏏

Cricket analogy: Any Dart class implicitly defines an interface, so class SpinBowler implements Bowler forces SpinBowler to provide its own full implementation of every member Bowler declares, including announce(), since implements takes only the contract, not the code.

Every class in Dart implicitly defines an interface consisting of its instance members. Any class can be used as an interface with implements, but doing so requires reimplementing every member from scratch; implements never brings along code, only the contract.

Abstract Classes vs Interfaces

Choosing extends versus implements really comes down to whether you want to reuse working code or merely satisfy a contract. A class can extend only one superclass but can implements many interfaces at once, so use implements when a class needs to satisfy multiple unrelated contracts and extends when it should inherit real, shared logic.

🏏

Cricket analogy: When several bowler subtypes share real, reusable logic like announce(), extending an abstract class Bowler is efficient because the shared method is inherited for free, whereas if a class needed to satisfy both Bowler and Fieldable contracts with implements Bowler, Fieldable, it would have to write every single method itself.

dart
abstract class Flyable {
  void fly();
}

abstract class Swimmable {
  void swim();
}

class Duck implements Flyable, Swimmable {
  @override
  void fly() => print('Duck flies low over the pond');

  @override
  void swim() => print('Duck paddles across the pond');
}

void main() {
  var duck = Duck();
  duck.fly();
  duck.swim();
}

A class can implements any number of interfaces but can only extends a single class. If two interfaces required by implements declare the same method signature differently, the implementing class must satisfy both, which can force you to redesign the interfaces rather than fight incompatible contracts.

  • An abstract class, declared with the abstract keyword, cannot be instantiated directly and may contain both abstract (bodiless) and concrete methods.
  • Abstract methods declare a signature without an implementation, forcing every concrete subclass to provide one via @override.
  • Every Dart class implicitly defines an interface made up of its members, usable via the implements keyword.
  • Unlike extends, implements never inherits implementation code; the implementing class must write every method itself.
  • A class can implements multiple interfaces at once but can extends only one superclass.
  • Use extends (often on an abstract class) when you want to share concrete code; use implements when you only need to guarantee a contract.
  • Attempting to instantiate an abstract class directly, like Bowler('X'), is a compile-time error in Dart.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#DartStudyNotes#AbstractClassesAndInterfaces#Abstract#Classes#Interfaces#Defining#OOP#StudyNotes#SkillVeris