Interface-based Polymorphism

Interface-based Polymorphism

About

  • Implicit Interfaces: All classes define interfaces
  • Multiple Inheritance: Implement many interfaces
  • Loose Coupling: Code to interfaces not implementations
  • Dart’s Approach: No separate interface keyword

Main Topics

  1. Basic Implementation

    • Definition: implements keyword
    • Example:
      class MockHttpClient implements HttpClient {
        // Must implement all members
      }
  2. Multiple Interfaces

    • Definition: Comma-separated list
    • Example:
      class Student implements Person, Learner {
        // Implement both interfaces
      }
  3. Abstract Classes as Interfaces

    • Definition: Partial implementations

    • Example:

      abstract class Repository {
        void save();
      }
      
      class UserRepo implements Repository {
        @override
        void save() {/*...*/}
      }
  4. Interface Contracts

    • Definition: Required member signatures
    • Example:
      class Cash implements PaymentMethod {
        @override
        void pay(double amount) {
          // Must implement
        }
      }
  5. Mixins vs Interfaces

    • Definition: Different reuse mechanisms
    • Example:
      // Interface defines contract
      // Mixin provides implementation

How to Use

  • Testing: Mock implementations
  • Plugins: Multiple backends
  • API Design: Stable interfaces
  • Evolution: Easier refactoring

How It Works

  1. Type System: Interface is type
  2. Verification: Compiler checks
  3. Flexibility: Runtime substitution
  4. Documentation: Implicit contracts

Example:

abstract class DataStore {
  Future<void> save(String key, String value);
}

class MemoryStore implements DataStore {
  final _storage = <String, String>{};

  @override
  Future<void> save(String key, String value) async {
    _storage[key] = value;
  }
}

class FileStore implements DataStore {
  @override
  Future<void> save(String key, String value) async {
    // File system implementation
  }
}

Conclusion

Interface-based polymorphism in Dart enables flexible, testable designs through abstract type contracts. By programming to interfaces rather than concrete implementations, Dart code becomes more modular and adaptable to change.