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;
this.name, this.age);
Animal(
void eat() {
'$name is eating');
print(}
void sleep() {
'$name is sleeping');
print(}
}
// Usage
= Animal('Buddy', 3);
Animal dog .eat(); // Output: Buddy is eating dog
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
'Flying...');
print(}
}
class Bird implements Flyable {
@override
void fly() {
'Bird is flying with wings');
print(}
}
class Airplane implements Flyable {
@override
void fly() {
'Airplane is flying with engines');
print(}
}
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() {
'Duck flying');
print(}
@override
void swim() {
'Duck swimming');
print(}
}
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;
this.name);
Animal(
// Abstract method - must be implemented by subclasses
void makeSound();
// Concrete method - can be inherited as-is
void sleep() {
'$name is sleeping');
print(}
// Another concrete method
void eat() {
'$name is eating');
print(}
}
class Dog extends Animal {
String name) : super(name);
Dog(
@override
void makeSound() {
'$name barks: Woof!');
print(}
// 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;
this.brand);
Vehicle(
void startEngine(); // Abstract - must implement
void displayInfo() { // Concrete - can inherit
'Brand: $brand');
print(}
}
// Interface - all methods must be implemented
class Drivable {
void drive() {
'Driving...');
print(}
}
class Car extends Vehicle implements Drivable {
String brand) : super(brand);
Car(
@override
void startEngine() {
'Car engine started');
print(}
@override
void drive() { // Must implement even though Drivable has implementation
'Car is driving');
print(}
}
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;
this.area); // Constructor available
Shape(
void displayArea() {
'Area: $area');
print(}
}
class Circle extends Shape {
double radius) : super(3.14159 * radius * radius);
Circle(}
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;
{required this.duration});
AnimatedWidget(
// Abstract method - each animated widget implements differently
, Animation<double> animation);
Widget buildAnimation(BuildContext context
// Concrete method - shared animation logic
@override
=> AnimatedWidgetState();
AnimatedWidgetState createState() }
// Interface for widgets that can handle gestures
class GestureHandler {
void onTap() {}
void onLongPress() {}
}
class AnimatedButton extends AnimatedWidget implements GestureHandler {
: super(duration: Duration(milliseconds: 300));
AnimatedButton()
@override
, Animation<double> animation) {
Widget buildAnimation(BuildContext context// Custom animation implementation
return Container();
}
@override
void onTap() {
'Button tapped');
print(}
@override
void onLongPress() {
'Button long pressed');
print(}
}
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.