Introduction
The concepts of abstract Class
es and interface
s are fundamental to object-oriented programming. They are used to define contracts and behaviors that classes must follow, but they serve different purposes and have distinct characteristics.
abstract Class
An abstract class
is a special type of class that cannot be instantiated directly. Instead, it acts as a blueprint or template for other classes. Its primary purpose is to provide a common base that can be shared by multiple subclasses, while also enforcing specific methods or behaviors that those subclasses must implement.
In Dart, abstract classes support single inheritance, meaning a class can extend only one abstract class
. They are versatile because they can include fields, constructors, and concrete methods (methods with implementation). Unlike interfaces, abstract classes can provide a partial implementation, allowing subclasses to inherit and reuse some behavior while requiring them to implement specific parts. This makes abstract classes a powerful tool for creating structured, reusable, and maintainable code.
Example
// Abstract class acting as a blueprint for vehicles
abstract class Vehicle {
String name; // Field
double maxSpeed; // Field
// Constructor
Vehicle(this.name, this.maxSpeed);
// Abstract method (must be implemented by subclasses)
void start();
// Concrete method (default implementation)
void stop() {
print('$name has stopped.');
}
// Another concrete method
void displayInfo() {
print('Vehicle: $name, Max Speed: $maxSpeed km/h');
}
}
// Subclass Car extending the abstract class Vehicle
class Car extends Vehicle {
Car(String name, double maxSpeed) : super(name, maxSpeed);
@override
void start() {
print('$name is starting... Vroom Vroom!');
}
}
// Subclass Bicycle extending the abstract class Vehicle
class Bicycle extends Vehicle {
Bicycle(String name, double maxSpeed) : super(name, maxSpeed);
@override
void start() {
print('$name is starting... Pedal Pedal!');
}
}
void main() {
// Create instances of Car and Bicycle
final car = Car('Tesla Model S', 250);
final bicycle = Bicycle('Mountain Bike', 30);
// Use methods from the abstract class and subclasses
car.displayInfo(); // Output: Vehicle: Tesla Model S, Max Speed: 250 km/h
car.start(); // Output: Tesla Model S is starting... Vroom Vroom!
car.stop(); // Output: Tesla Model S has stopped.
bicycle.displayInfo(); // Output: Vehicle: Mountain Bike, Max Speed: 30 km/h
bicycle.start(); // Output: Mountain Bike is starting... Pedal Pedal!
bicycle.stop(); // Output: Mountain Bike has stopped.
}
interface
An interface
is a contract or blueprint that defines a set of methods and properties a class must implement. It specifies what a class should do without dictating how it should do it. Interfaces enforce a consistent structure across unrelated classes, enabling polymorphism and allowing different classes to be used interchangeably as long as they implement the same interface.
Key characteristics of interfaces include:
- They cannot be instantiated directly.
- A class can implement multiple interfaces, allowing it to adhere to multiple contracts simultaneously.
- Pure interfaces (in most languages) cannot have fields or constructors; they focus solely on defining behavior.
- Interfaces promote loose coupling and modularity by separating what a class should do from how it does it.
- They define a strict contract without implementation, ensuring flexibility and consistency in design.
By using interfaces, developers can create systems where different classes work together seamlessly, as long as they adhere to the same contract, making code more modular, reusable, and maintainable.
Example (abstract interface class
)
// Interface defining a contract for objects that can be drawn
abstract interface class Drawable {
void draw(); // Contract method (no implementation)
}
// Interface defining a contract for objects that can be resized
abstract interface class Resizable {
void resize(double scale); // Contract method (no implementation)
}
// Class Circle implementing both Drawable and Resizable interfaces
class Circle implements Drawable, Resizable {
@override
void draw() {
print('Drawing a Circle');
}
@override
void resize(double scale) {
print('Resizing Circle by scale $scale');
}
}
// Class Square implementing the Drawable interface
class Square implements Drawable {
@override
void draw() {
print('Drawing a Square');
}
}
void main() {
// Create instances of Circle and Square
final circle = Circle();
final square = Square();
// Use methods from the interfaces
circle.draw(); // Output: Drawing a Circle
circle.resize(2.0); // Output: Resizing Circle by scale 2.0
square.draw(); // Output: Drawing a Square
// Polymorphism in action
List<Drawable> shapes = [circle, square];
for (var shape in shapes) {
shape.draw(); // Calls the draw() method of each shape
}
}
interface class
An interface class
can include both concrete methods (with implementation) and abstract methods (without implementation). It can also have fields and constructors. A class can implement multiple interface class
es, and the interface class
itself can be instantiated directly unless marked as abstract
.
The primary use case for an interface class
is when you want to define a contract while also providing default behavior that implementing classes can use or override. In other words, it defines a contract with optional default behavior, making it ideal for scenarios where you want to share common functionality across multiple classes while still allowing flexibility for customization.
If the interface class
has no abstract methods (only concrete methods), it can be instantiated directly. However, if the interface class
contains abstract methods, it cannot be instantiated directly unless those methods are implemented.
Example
Can Be Instantiated
interface class Drawable {
void draw() {
print('Drawing something');
}
}
void main() {
final drawable = Drawable(); // Can be instantiated
drawable.draw(); // Output: Drawing something
}
Cannot Be Instantiated
interface class Drawable {
void draw(); // Abstract method
}
void main() {
// final drawable = Drawable(); // Error: Cannot instantiate an abstract class
}
Differences
Abstract classes are used when you want to provide a base implementation that subclasses can reuse, enforce specific methods that subclasses must implement, and share common behavior among related classes while offering a partial implementation. On the other hand, interfaces are used when you want to define a strict contract that multiple unrelated classes must follow, and enforce a consistent structure across different classes without providing any implementation. Abstract classes are ideal for creating a shared foundation, while interfaces are perfect for ensuring flexibility and consistency across diverse classes.
Feature | abstract class |
abstract interface class |
interface class |
---|---|---|---|
Purpose | Provides a partial implementation. | Defines a pure interface (no implementation). | Defines a contract with optional default behavior. |
Methods | Can have abstract and concrete methods. | Can only have abstract methods. | Can have concrete and abstract methods. |
Fields | Can have fields and constructors. | Cannot have fields or constructors. | Can have fields and constructors. |
Instantiation | Cannot be instantiated directly. | Cannot be instantiated directly. | Can be instantiated directly (unless marked as abstract ). |
Inheritance | A class can extend only one abstract class. | A class can implement multiple abstract interface classes. | A class can implement multiple interface classes. |
Use Case | When you want to share common behavior among subclasses. | When you want to enforce a strict contract. | When you want to define a contract with optional default behavior. |
Top comments (0)