๐๏ธ Lesson 5: Object-Oriented Programming Basics
Why Object-Oriented Programming?
๐ง The Core Idea
OOP organizes code into objectsโself-contained units that bundle data (properties) and behavior (methods) together. Instead of scattered variables and functions, you create reusable blueprints called classes.
Class = Blueprint
A plan that describes how to build something. The class Car defines what every car has.
Object = Instance
An actual car built from the blueprint. var myCar = Car('Tesla', 2026) creates one.
Properties = Attributes
Data stored in the object. Color, model, year, speed.
Methods = Actions
Things the object can do. Accelerate, brake, honk.
Anatomy of a Class
๐ง Every class has three main parts:
1. Properties (also called fields or instance variables) โ the data.
2. Constructor โ a special method that creates and initializes objects.
3. Methods โ functions that define what objects can do.
๐ Member Details
Click on any property, constructor, or method to see what it does.
Complete Class Example with Line-by-Line Explanation
// Defining a class called Animal
class Animal {
// Properties (instance variables)
String name;
int age;
String species;
// Constructor โ creates new Animal objects
Animal(this.name, this.age, this.species);
// Method โ an action the animal can do
void makeSound() {
print('\$name makes a sound');
}
// Method with a parameter
void eat(String food) {
print('\$name eats \$food');
}
// Getter โ a computed property (no parentheses)
String get description {
return '\$name is a \${age}-year-old \$species';
}
}
๐ Line-by-Line
class keyword defines a new typethis refers to the current instance\$name interpolates the property value()Using the Class
// Creating objects (instances) of the Animal class
void main() {
// Create two different Animal objects
var cat = Animal('Whiskers', 3, 'Feline');
var dog = Animal('Buddy', 5, 'Canine');
// Accessing properties
print(cat.name); // Whiskers
print(dog.age); // 5
// Calling methods
cat.makeSound(); // Whiskers makes a sound
dog.eat('kibble'); // Buddy eats kibble
// Using the getter (no parentheses!)
print(cat.description); // Whiskers is a 3-year-old Feline
}
โ๏ธ Try It: Create Your Own Animal
Constructors: Different Ways to Create Objects
๐ง Constructors are special methods named after the class
Dart provides several constructor types for different scenarios. The most common is the default constructor, but you can also create named constructors for alternative initialization paths.
1๏ธโฃ Default Constructor
The most common type. Automatically provided if you don't define one. Use this.property for shorthand initialization.
class Point {
double x;
double y;
// Default constructor with shorthand syntax
Point(this.x, this.y);
}
var p = Point(3.0, 4.0); // x=3.0, y=4.0
2๏ธโฃ Named Constructors
Give your class multiple ways to be created. Use the syntax ClassName.constructorName().
class Point {
double x, y;
Point(this.x, this.y);
// Named constructor: creates origin point
Point.origin()
: x = 0,
y = 0;
// Named constructor: creates point from map
Point.fromMap(Map<String, double> map)
: x = map['x'] ?? 0,
y = map['y'] ?? 0;
}
var origin = Point.origin(); // x=0, y=0
var fromMap = Point.fromMap({'x': 5, 'y': 10}); // x=5, y=10
3๏ธโฃ Factory Constructors
Use factory when you don't always want to create a new instance. Common for caching, singletons, or returning subtypes.
class Logger {
static Logger? _instance;
// Private constructor (can't be called from outside)
Logger._();
// Factory returns the same instance every time
factory Logger() {
_instance ??= Logger._();
return _instance!;
}
}
var log1 = Logger();
var log2 = Logger();
print(log1 == log2); // true โ same instance!
4๏ธโฃ Constant Constructors
Use const to create compile-time constants. All properties must be final. These are immutable and share memory.
class ImmutablePoint {
final double x;
final double y;
const ImmutablePoint(this.x, this.y);
}
const p1 = ImmutablePoint(0, 0);
const p2 = ImmutablePoint(0, 0);
print(p1 == p2); // true โ identical constants share memory
Inheritance: Reusing Code with Hierarchies
๐ง Inheritance lets a class reuse properties and methods from a parent class
Use the extends keyword. The child class automatically gets everything the parent has, and can add or override its own behavior. Use super to refer to the parent class.
โ Without Inheritance (Duplication)
class Dog {
String name;
void eat() { print('Eating...'); }
void sleep() { print('Sleeping...'); }
void bark() { print('Woof!'); }
}
class Cat {
String name;
void eat() { print('Eating...'); }
void sleep() { print('Sleeping...'); }
void meow() { print('Meow!'); }
}
๐ฐ eat() and sleep() duplicated in every class!
โ With Inheritance (Clean)
class Animal {
String name;
Animal(this.name);
void eat() { print('Eating...'); }
void sleep() { print('Sleeping...'); }
}
class Dog extends Animal {
Dog(super.name);
void bark() { print('Woof!'); }
}
class Cat extends Animal {
Cat(super.name);
void meow() { print('Meow!'); }
}
๐ Shared code in parent, unique behavior in children!
๐ณ Class Hierarchy
๐ Class Details
Click on any class to see its role in the hierarchy.
@override. This is how a Dog's makeSound() says "Woof!" while a Cat's says "Meow!".
Complete Inheritance Example with Override
class Animal {
String name;
Animal(this.name);
void makeSound() {
print('\$name makes a generic sound');
}
}
class Dog extends Animal {
Dog(super.name); // Forward name to parent constructor
@override
void makeSound() {
print('\$name says: Woof! Woof!'); // Override!
}
}
class Cat extends Animal {
Cat(super.name);
@override
void makeSound() {
print('\$name says: Meow! Meow!');
}
}
void main() {
var dog = Dog('Buddy');
var cat = Cat('Whiskers');
dog.makeSound(); // Buddy says: Woof! Woof!
cat.makeSound(); // Whiskers says: Meow! Meow!
}
Polymorphism: One Interface, Many Behaviors
๐ง "Poly" = many, "morph" = form
Polymorphism lets you treat objects of different classes through a shared parent type. You can write code that works with Animal without knowing if it's a Dog, Cat, or Birdโeach responds in its own way.
animal.makeSound() on a variable typed as Animal, Dart calls the actual object's version of the method, not the parent's. This is called dynamic dispatch.
// Polymorphism: Treat all animals the same way
void makeAllSpeak(List<Animal> animals) {
for (var animal in animals) {
animal.makeSound(); // Each animal speaks in its own way!
}
}
void main() {
var animals = [
Dog('Buddy'),
Cat('Whiskers'),
Dog('Rex'),
Cat('Luna'),
];
makeAllSpeak(animals);
// Buddy says: Woof! Woof!
// Whiskers says: Meow! Meow!
// Rex says: Woof! Woof!
// Luna says: Meow! Meow!
}
๐ฆ Build Your Zoo
No animals in the zoo yet.
๐ต Make Them Speak!
Abstract Classes: Defining Contracts
๐ง An abstract class defines WHAT must be done, not HOW
Mark a class with abstract to prevent it from being instantiated directly. It can declare methods without implementationsโforcing every subclass to provide their own. Think of it as a contract: "If you extend me, you MUST implement these methods."
๐ The Contract (Abstract)
abstract class Shape {
// Abstract getters โ no body!
double get area;
double get perimeter;
// Concrete method โ has a body
void display() {
print('Area: \$area');
print('Perimeter: \$perimeter');
}
}
โ ๏ธ Cannot do: var s = Shape(); โ abstract!
๐ต Circle Implementation
class Circle extends Shape {
double radius;
Circle(this.radius);
@override
double get area => 3.14159 * radius * radius;
@override
double get perimeter => 2 * 3.14159 * radius;
}
๐ฆ Rectangle Implementation
class Rectangle extends Shape {
double width, height;
Rectangle(this.width, this.height);
@override
double get area => width * height;
@override
double get perimeter => 2 * (width + height);
}
โ๏ธ Try It: Create a Shape and Display It
๐ฏ OOP Concept Quiz
Score: 0/5 | Hints: 3
Loading question...
Practice Projects
Apply what you've learned by building these hands-on projects.