Answer
Overview
Abstraction is the OOP principle of hiding complex implementation details and exposing only the essential interface. In Dart, abstraction is achieved through abstract classes and interfaces.
Abstract Class
An abstract class cannot be instantiated — it defines a contract that subclasses must fulfill.
dart// Abstract class — cannot be instantiated directly abstract class Shape { // Abstract methods — no implementation (must be overridden) double area(); double perimeter(); // Concrete method — shared by all subclasses void describe() { print('Area: ${area().toStringAsFixed(2)}, Perimeter: ${perimeter().toStringAsFixed(2)}'); } } class Circle extends Shape { final double radius; Circle(this.radius); double area() => 3.14159 * radius * radius; double perimeter() => 2 * 3.14159 * radius; } class Rectangle extends Shape { final double width, height; Rectangle(this.width, this.height); double area() => width * height; double perimeter() => 2 * (width + height); } void main() { // final shape = Shape(); // ❌ Cannot instantiate abstract class final shapes = [Circle(5), Rectangle(4, 6)]; for (final s in shapes) s.describe(); // Polymorphic — abstraction in action }
Interface (abstract class + implements)
Dart uses abstract classes as interfaces:
dart// Interface — pure abstraction (all abstract methods) abstract class DatabaseAdapter { Future<void> connect(String url); Future<List<Map>> query(String sql); Future<void> close(); } // SQLite implementation class SQLiteAdapter implements DatabaseAdapter { Future<void> connect(String url) async { /* SQLite connect */ } Future<List<Map>> query(String sql) async { return []; } Future<void> close() async { /* Close */ } } // Firestore implementation class FirestoreAdapter implements DatabaseAdapter { Future<void> connect(String url) async { /* Firestore connect */ } Future<List<Map>> query(String sql) async { return []; } Future<void> close() async { /* Close */ } } // Business logic only knows about the interface — not the implementation class UserRepository { final DatabaseAdapter _db; // Abstraction — not concrete impl UserRepository(this._db); Future<List<Map>> getUsers() => _db.query('SELECT * FROM users'); }
Abstract vs Interface vs Mixin
| Feature | text | text | text |
|---|---|---|---|
| Can have implementation | ✅ Yes | ❌ No (by convention) | ✅ Yes |
| Instantiable | ❌ No | ❌ No | ❌ No |
| Used with | text | text | text |
| Multiple | One text | Many text | Many text |
Real benefit: Abstraction lets you change the underlying implementation (swap SQLite for Firestore) without changing any business logic code — as long as the interface is honored.