22  Interface & Abstract Class

In Dart, Class and Interface serve different purposes in object-oriented programming. Let me explain the key differences:

22.0.1 Class

A class is a blueprint that defines both the structure (properties) and behavior (methods) of objects. It provides concrete implementations.

class Animal {
  String name;
  int age;
  
  Animal(this.name, this.age);
  
  void eat() {
    print('$name is eating');
  }
  
  void sleep() {
    print('$name is sleeping');
  }
}

// Usage
Animal dog = Animal('Buddy', 3);
dog.eat(); // Output: Buddy is eating

22.0.2 Interface

An interface defines a contract - it specifies what methods a class must implement, but doesn’t provide the actual implementation. In Dart, any class can be used as an interface using the implements keyword.

// This class serves as an interface
class Flyable {
  void fly() {
    // This implementation will be ignored when used as interface
    print('Flying...');
  }
}

class Bird implements Flyable {
  @override
  void fly() {
    print('Bird is flying with wings');
  }
}

class Airplane implements Flyable {
  @override
  void fly() {
    print('Airplane is flying with engines');
  }
}

22.0.3 Key Differences

Inheritance vs Implementation: - Class: Use extends for inheritance (inherits both structure and behavior) - Interface: Use implements for contract enforcement (must provide your own implementation)

Code Reuse: - Class: Provides ready-to-use methods and properties - Interface: Forces you to write your own implementation

Multiple Implementation: - Class: Can only extend one class (single inheritance) - Interface: Can implement multiple interfaces

// Multiple interface implementation
class Duck implements Flyable, Swimmable {
  @override
  void fly() {
    print('Duck flying');
  }
  
  @override
  void swim() {
    print('Duck swimming');
  }
}

22.0.4 Visual Representation

Class (extends)
    Parent Class
         |
    Child Class (inherits methods + properties)

Interface (implements)
    Interface Contract
         |
    Implementing Class (must provide own implementation)

22.0.5 When to Use Each

Use Class when: - You want to share common implementation across related objects - You have a clear parent-child relationship - You want code reuse

Use Interface when: - You want to enforce a contract across unrelated classes - You need multiple inheritance-like behavior - You want to define “what” without “how”

This is particularly useful in Flutter where you might have different widgets that need to implement the same interface but have completely different implementations.

Great question! Abstract classes in Dart are indeed similar to interfaces but with some key differences. Let me break this down:

22.1 Abstract Class

An abstract class is a class that cannot be instantiated directly and may contain both abstract methods (without implementation) and concrete methods (with implementation).

abstract class Animal {
  String name;
  
  Animal(this.name);
  
  // Abstract method - must be implemented by subclasses
  void makeSound();
  
  // Concrete method - can be inherited as-is
  void sleep() {
    print('$name is sleeping');
  }
  
  // Another concrete method
  void eat() {
    print('$name is eating');
  }
}

class Dog extends Animal {
  Dog(String name) : super(name);
  
  @override
  void makeSound() {
    print('$name barks: Woof!');
  }
  
  // Inherits sleep() and eat() methods
}

22.1.1 Key Differences

Implementation Requirements:

// Abstract class - can have both abstract and concrete methods
abstract class Vehicle {
  String brand;
  
  Vehicle(this.brand);
  
  void startEngine(); // Abstract - must implement
  
  void displayInfo() { // Concrete - can inherit
    print('Brand: $brand');
  }
}

// Interface - all methods must be implemented
class Drivable {
  void drive() {
    print('Driving...');
  }
}

class Car extends Vehicle implements Drivable {
  Car(String brand) : super(brand);
  
  @override
  void startEngine() {
    print('Car engine started');
  }
  
  @override
  void drive() { // Must implement even though Drivable has implementation
    print('Car is driving');
  }
}

Inheritance vs Implementation: - Abstract class: Use extends (single inheritance) - Interface: Use implements (multiple implementation)

Constructor Support: - Abstract class: Can have constructors - Interface: Constructors are ignored when used as interface

abstract class Shape {
  double area;
  
  Shape(this.area); // Constructor available
  
  void displayArea() {
    print('Area: $area');
  }
}

class Circle extends Shape {
  Circle(double radius) : super(3.14159 * radius * radius);
}

22.1.2 Comparison Table

Feature Abstract Class Interface
Keyword abstract class Any class used with implements
Usage extends implements
Multiple inheritance No (single extends) Yes (multiple implements)
Method implementation Mixed (abstract + concrete) All must be implemented
Constructor Supported Ignored
Properties Can have instance variables Properties must be implemented
Instantiation Cannot instantiate Cannot instantiate directly

22.1.3 Visual Representation

Abstract Class Hierarchy:
    Abstract Animal
    ├── abstract makeSound()
    └── concrete sleep()
         |
    Dog extends Animal
    ├── implements makeSound()
    └── inherits sleep()

Interface Implementation:
    Interface Contract
    ├── method1()
    ├── method2()
    └── method3()
         |
    Class implements Interface
    ├── must implement method1()
    ├── must implement method2()
    └── must implement method3()

22.1.4 When to Use Each

Use Abstract Class when: - You want to share common implementation among related classes - You have a clear inheritance hierarchy - You want to provide some default behavior while enforcing certain contracts

Use Interface when: - You want to define a contract for unrelated classes - You need multiple inheritance-like behavior - You want to enforce “what” without providing any “how”

22.1.5 Real-world Flutter Example

// Abstract class for widgets that can be animated
abstract class AnimatedWidget extends StatefulWidget {
  final Duration duration;
  
  AnimatedWidget({required this.duration});
  
  // Abstract method - each animated widget implements differently
  Widget buildAnimation(BuildContext context, Animation<double> animation);
  
  // Concrete method - shared animation logic
  @override
  AnimatedWidgetState createState() => AnimatedWidgetState();
}

// Interface for widgets that can handle gestures
class GestureHandler {
  void onTap() {}
  void onLongPress() {}
}

class AnimatedButton extends AnimatedWidget implements GestureHandler {
  AnimatedButton() : super(duration: Duration(milliseconds: 300));
  
  @override
  Widget buildAnimation(BuildContext context, Animation<double> animation) {
    // Custom animation implementation
    return Container();
  }
  
  @override
  void onTap() {
    print('Button tapped');
  }
  
  @override
  void onLongPress() {
    print('Button long pressed');
  }
}

The key insight is that abstract classes provide a middle ground between regular classes and interfaces - they can enforce contracts while still providing shared implementation.