Lesson 13 of 51 intermediate

Inheritance & Mixins

Sharing and Combining Abilities Across Classes

Open interactive version (quiz + challenge)

Real-world analogy

Inheritance is like a family tree: a child inherits traits from a parent but can develop their own unique features too. A Dog class inherits from Animal and gets walk() for free, but adds its own bark() method. Mixins are like skill badges -- a Scout can earn a Swimming badge and a Cooking badge independently. In team_mvp_kit, BLoC classes extend Bloc (inheritance) while mixins add cross-cutting capabilities like logging.

What is it?

Inheritance lets a class absorb the properties and methods of another class, creating a parent-child relationship. Mixins let you add capabilities to a class without a strict parent-child hierarchy -- like plugging in USB accessories. Abstract classes define contracts without implementations. Dart supports single inheritance (one parent) but unlimited mixins. Together, these tools let you share code, enforce contracts, and compose behaviors flexibly.

Real-world relevance

In team_mvp_kit, inheritance and interfaces are the backbone of Clean Architecture. Abstract repository classes in the domain layer define what operations are available. Concrete classes in the data layer implement those interfaces with real API calls via Dio and local storage via Hive. BLoC classes extend Bloc from the bloc package. Sealed classes like AuthState enable type-safe state management where the compiler ensures you handle every possible state.

Key points

Code example

abstract class AuthRepository {
  Future<UserEntity> login(String email, String password);
  Future<void> logout();
  Future<bool> isLoggedIn();
}

mixin CacheManager {
  final Map<String, dynamic> _cache = {};

  void cacheData(String key, dynamic value) {
    _cache[key] = value;
  }

  dynamic getCachedData(String key) {
    return _cache[key];
  }

  void clearCache() {
    _cache.clear();
  }
}

class AuthRepositoryImpl
    implements AuthRepository
    with CacheManager {
  final Dio dio;

  AuthRepositoryImpl({required this.dio});

  @override
  Future<UserEntity> login(String email, String password) async {
    final response = await dio.post('/auth/login', data: {
      'email': email,
      'password': password,
    });
    final user = UserModel.fromJson(response.data);
    cacheData('current_user', user);
    return user;
  }

  @override
  Future<void> logout() async {
    await dio.post('/auth/logout');
    clearCache();
  }

  @override
  Future<bool> isLoggedIn() async {
    return getCachedData('current_user') != null;
  }
}

Line-by-line walkthrough

  1. 1. Define abstract class AuthRepository -- this is the interface that lives in the domain layer
  2. 2. Declare abstract method login that takes email and password, returns Future
  3. 3. Declare abstract method logout that returns Future
  4. 4. Declare abstract method isLoggedIn that returns Future
  5. 5. Define mixin CacheManager -- this provides caching capability to any class that uses it
  6. 6. Create a private cache Map to store key-value pairs
  7. 7. Define cacheData method to store a value under a key
  8. 8. Define getCachedData method to retrieve a value by key
  9. 9. Define clearCache method to empty the cache
  10. 10. AuthRepositoryImpl implements AuthRepository and uses CacheManager mixin
  11. 11. Declare a Dio instance for HTTP requests
  12. 12. Constructor requires a Dio instance via named parameter
  13. 13. Implement login: make a POST request to /auth/login with credentials
  14. 14. Parse the response data into a UserModel using fromJson factory
  15. 15. Cache the current user using the mixin's cacheData method
  16. 16. Return the user (UserModel extends UserEntity)
  17. 17. Implement logout: make a POST request to /auth/logout
  18. 18. Clear the cache using the mixin's clearCache method
  19. 19. Implement isLoggedIn: check if current_user exists in the cache
  20. 20. Return true if cached data is not null, false otherwise

Spot the bug

abstract class Repository {
  void save(String data);
}

class FileRepository extends Repository {
  void save(String data) {
    print('Saving to file: $data');
  }
}

class DbRepository extends Repository {
  void save(int data) {
    print('Saving to database: $data');
  }
}
Need a hint?
Look at DbRepository's save method signature. Does it match the parent class?
Show answer
DbRepository.save takes an int parameter but the abstract class Repository.save requires a String parameter. This will cause a compile error because the override does not match the parent's method signature. Change DbRepository.save to accept String data instead of int data, and add @override annotations.

Explain like I'm 5

Imagine you are building with LEGO. Inheritance is like getting a starter kit from your parent -- you get all their basic pieces and can add your own cool parts on top. A mixin is like borrowing a special LEGO pack from a friend -- you add those pieces to your creation without changing who your parent is. An abstract class is like a building instruction page that says 'put a door here' but does not give you the actual door -- you have to figure out what kind of door to use yourself.

Fun fact

Dart's mixin system was inspired by Strongtalk, an experimental variant of Smalltalk developed at Sun Microsystems in the 1990s. The researchers who created Strongtalk later joined Google and influenced Dart's design. So when you use mixins in Dart, you are using an idea that has been refined for over 30 years.

Hands-on challenge

Create an abstract class Vehicle with properties: make (String), year (int), and an abstract method fuelEfficiency(). Create a mixin Electric with a method charge() that prints a message. Create a class Tesla that extends Vehicle, applies the Electric mixin, and implements fuelEfficiency(). Create a class Honda that extends Vehicle with a different fuelEfficiency(). Demonstrate polymorphism by putting both in a List and calling fuelEfficiency() on each.

More resources

Open interactive version (quiz + challenge) ← Back to course: Flutter & Dart