Welcome to Day 5 of the "Hundred Days of Flutter" course! Today, we'll explore Object-Oriented Programming (OOP) concepts in Dart, which are essential for building well-structured and maintainable Flutter applications.
Classes are the building blocks of OOP in Dart. They define the structure and behavior of objects.
class Person {
// Properties (instance variables)
String name;
int age;
// Constructor
Person(this.name, this.age);
// Methods
void sayHello() {
print('Hello, my name is $name');
}
// Getter
String get info => '$name is $age years old';
// Setter
set setAge(int value) {
if (value >= 0) {
age = value;
}
}
}
void main() {
// Creating an object
final person = Person('John', 25);
person.sayHello(); // Output: Hello, my name is John
print(person.info); // Output: John is 25 years old
person.setAge = 26;
}
Dart uses the underscore (_) prefix to make members private:
class BankAccount {
String _accountNumber; // Private property
double _balance; // Private property
BankAccount(this._accountNumber, this._balance);
// Public getter
double get balance => _balance;
// Public method
void deposit(double amount) {
if (amount > 0) {
_balance += amount;
}
}
}
Dart provides several types of constructors:
class Car {
String brand;
String model;
// Default constructor
Car(this.brand, this.model);
// Named constructor
Car.toyota(this.model) : brand = 'Toyota';
// Factory constructor
factory Car.fromJson(Map<String, dynamic> json) {
return Car(json['brand'], json['model']);
}
}
class Point {
final double x;
final double y;
Point(double x, double y)
: x = x,
y = y,
assert(x >= 0),
assert(y >= 0);
}
Dart supports single inheritance and interfaces.
class Animal {
String name;
Animal(this.name);
void makeSound() {
print('Some sound');
}
}
class Dog extends Animal {
String breed;
Dog(String name, this.breed) : super(name);
@override
void makeSound() {
print('Woof!');
}
void fetch() {
print('$name is fetching the ball');
}
}
void main() {
final dog = Dog('Rex', 'German Shepherd');
dog.makeSound(); // Output: Woof!
dog.fetch(); // Output: Rex is fetching the ball
}
abstract class Shape {
double get area;
double get perimeter;
}
class Circle extends Shape {
final double radius;
Circle(this.radius);
@override
double get area => 3.14 * radius * radius;
@override
double get perimeter => 2 * 3.14 * radius;
}
class Rectangle extends Shape {
final double width;
final double height;
Rectangle(this.width, this.height);
@override
double get area => width * height;
@override
double get perimeter => 2 * (width + height);
}
Dart doesn't have a dedicated interface
keyword. Instead, any class can be used as an interface.
class Flyable {
void fly() {
print('Flying');
}
}
class Bird implements Flyable {
@override
void fly() {
print('Bird is flying');
}
}
class Airplane implements Flyable {
@override
void fly() {
print('Airplane is flying');
}
}
Mixins are a way to reuse code in multiple class hierarchies:
mixin Swimming {
void swim() {
print('Swimming');
}
}
mixin Flying {
void fly() {
print('Flying');
}
}
class Duck extends Animal with Swimming, Flying {
Duck(String name) : super(name);
@override
void makeSound() {
print('Quack!');
}
}
void main() {
final duck = Duck('Donald');
duck.swim(); // Output: Swimming
duck.fly(); // Output: Flying
duck.makeSound(); // Output: Quack!
}
Static members belong to the class itself, not to instances:
class MathUtils {
static const double pi = 3.14159;
static double square(double number) {
return number * number;
}
static double sum(List<double> numbers) {
return numbers.reduce((a, b) => a + b);
}
}
void main() {
print(MathUtils.pi); // Output: 3.14159
print(MathUtils.square(5)); // Output: 25
print(MathUtils.sum([1, 2, 3, 4, 5])); // Output: 15
}
Let's test your understanding of today's concepts:
What is the purpose of the 'extends' keyword in Dart?
Which of the following is true about abstract classes in Dart?
What is the purpose of mixins in Dart?
Create a shape calculator that demonstrates your understanding of OOP concepts:
Shape
class with abstract methods for area and perimeterShapeCalculator
class that can:
Here's a starting point:
abstract class Shape {
double get area;
double get perimeter;
String get name;
}
class Circle extends Shape {
final double radius;
Circle(this.radius);
@override
double get area => 3.14 * radius * radius;
@override
double get perimeter => 2 * 3.14 * radius;
@override
String get name => 'Circle';
}
class ShapeCalculator {
final List<Shape> shapes = [];
void addShape(Shape shape) {
shapes.add(shape);
}
double get totalArea {
return shapes.fold(0, (sum, shape) => sum + shape.area);
}
Shape get largestShape {
return shapes.reduce((a, b) => a.area > b.area ? a : b);
}
void printShapes() {
shapes.forEach((shape) {
print('${shape.name}:');
print(' Area: ${shape.area}');
print(' Perimeter: ${shape.perimeter}');
print('');
});
}
}
extends
keywordimplements
keywordTomorrow, we'll start exploring Flutter's widget system and begin building our first Flutter application!
Master Dart's collection types and null safety features to write more robust and type-safe code in your Flutter applications.
Start Previous DayLearn about Flutter's widget tree structure and how to create stateless widgets to build the foundation of your Flutter applications.
Start Next Day