


When learning Dart OOP for Flutter, abstract classes, extends, and implements can be confusing.
What exactly is an abstract class? And when should you use extends instead of implements?
This guide explains these Dart OOP concepts using simple language and practical Flutter examples, so you can write cleaner, reusable, and testable code.
An abstract class acts as a blueprint for other classes. You cannot create an instance of it directly. Understanding Dart OOP becomes easier when you see how abstract classes define common behavior for related classes.
You can use an abstract class to:
abstract class Animal {
void makeSound();
}Animal animal = Animal();class Dog extends Animal {
@override
void makeSound() {
print("Woof!");
}
}abstract class Animal {
void makeSound();
void breathe() {
print("Breathing...");
}
}class Cat extends Animal {
@override
void makeSound() {
print("Meow");
}
}class Animal {
void makeSound();
}abstract class Animal {
void makeSound();
}The extends keyword is used for inheritance.
Think of it as:
class Animal {
void eat() {
print("Eating...");
}
}
class Dog extends Animal {
void bark() {
print("Woof!");
}
}A common Flutter example is extending framework classes such as StatelessWidget.
The implements keyword is useful when a class needs to conform to a defined API or contract.
For example:
abstract class Animal {
void makeSound();
}
class Bird implements Animal {
@override
void makeSound() {
print("Chirp chirp");
}
}Here, Bird provides its own implementation of the required behavior.
This pattern is particularly useful for:
The easiest way to understand the difference is to focus on inheritance versus contract.
With extends, a class builds on an existing class.
class Dog extends Animal {
// Add or override behavior
}With implements, a class conforms to the specified API and provides the required implementations.
class MockUserRepository implements UserRepository {
// Provide the required behavior
}Extends | Implements |
|---|---|
Used for inheritance |
Used for contracts and APIs |
Useful for code reuse |
Useful for independent implementations |
Builds on an existing class |
Defines required behavior |
Common in Flutter widgets |
Common in repository and testing patterns |
For more details, see the Official Dart documentation on classes.
Is this class a specialized version of another class?
→ Consider extends.
“Does this class need to follow a defined contract?”
→ Consider implements.
“Use extends for inheritance and reuse; use implements when you need a class to conform to a defined contract.”
The answer depends on what you’re trying to achieve.
A repository abstraction can define what the application needs without coupling it to a specific data source.
abstract class UserRepository {
Future<User> getUser(int id);
}class FirebaseUserRepository implements UserRepository {
@override
Future<User> getUser(int id) async {
// Fetch user from Firebase
}
}This separation can make the application easier to test and maintain.
When a class genuinely specializes an existing class and benefits from its behavior, inheritance can be appropriate.
For example:
class CustomButton extends StatelessWidget {
// Override build()
}Let’s put the idea together.
abstract class UserRepository {
Future<User> getUser(int id);
}class FirebaseUserRepository implements UserRepository {
@override
Future<User> getUser(int id) async {
return User(
id: id,
name: "John Doe",
);
}
}class MockUserRepository implements UserRepository {
@override
Future<User> getUser(int id) async {
return User(
id: id,
name: "Mock User",
);
}
}This structure separates the contract from the implementation.
It can help make your code:
Keep these three ideas in mind:
Use an abstract class when you need a base abstraction or contract.
Use extends when you need inheritance and reusable behavior.
Use implements when a class needs to follow a defined contract.
Need a shared base implementation?
→ Consider extends.
Need a contract between components?
→ Consider implements.
Need testable alternative implementations?
→ Consider an abstract repository contract with separate implementations.
Try these concepts in your next Flutter project:
Understanding Dart OOP is one step toward building maintainable software.
Need help building scalable digital products? Talk to our engineering team to explore how we can help.